简体   繁体   English

如何在Spring Data Mongo DB中聚合嵌套对象并避免PropertyReferenceException?

[英]How to aggregate in spring data mongo db a nested object and avoid a PropertyReferenceException?

I am creating a new endpoint in springboot that will return simple stats on users generated from an aggregate query in a mongo database. 我正在springboot中创建一个新端点,该端点将对从mongo数据库中的聚合查询生成的用户返回简单的统计信息。 However I get a PropertyReferenceException . 但是我得到了PropertyReferenceException I have read multiple stackoverflow questions about it, but didn't find one that solved this problem. 我已经阅读了关于它的多个stackoverflow问题,但没有找到解决该问题的方法。

We have a mongo data scheme like this: 我们有一个像这样的mongo数据方案:

{ 
"_id" : ObjectId("5d795993288c3831c8dffe60"), 
"user" : "000001", 
"name" : "test", 
"attributes" : { 
    "brand" : "Chrome",
    "language" : "English" }
}

The database is filled with multiple users and we want using Springboot aggregate the stats of users per brand . 该数据库充满了多个用户,我们希望使用Springboot汇总每个brand的用户统计信息。 There could be any number of attributes in the attributes object. attributes对象中可以有任意数量的属性。

Here is the aggregation we are doing 这是我们正在做的汇总

Aggregation agg = newAggregation(
    group("attributes.brand").count().as("number"),
    project("number").and("type").previousOperation()
);

AggregationResults<Stats> groupResults
    = mongoTemplate.aggregate(agg, Profile.class, Stats.class);

return groupResults.getMappedResults();

Which produces this mongo query which works: 产生此mongo查询的方法:

> db.collection.aggregate([ 
{ "$group" : { "_id" : "$attributes.brand" , "number" : { "$sum" : 1}}} ,
{ "$project" : { "number" : 1 , "_id" : 0 , "type" : "$_id"}} ])

{ "number" : 4, "type" : "Chrome" }
{ "number" : 2, "type" : "Firefox" }

However when running a simple integration test we get this error: 但是,在运行简单的集成测试时,会出现以下错误:

org.springframework.data.mapping.PropertyReferenceException: No property brand found for type String! Traversed path: Profile.attributes.

From what I understand, it seems that since attributes is a Map<String, String> there might be a schematic problem. 据我了解,似乎由于attributesMap<String, String>所以可能存在一个示意图问题。 And in the mean time I can't modify the Profile object. 同时,我无法修改Profile对象。

Is there something I am missing in the aggregation, or anything I could change in my Stats object? 聚合中是否缺少某些内容,或者我可以在Stats对象中更改的任何内容?

For reference, here are the data models we're using, to work with JSON and jackson. 作为参考,以下是我们正在使用的用于JSON和jackson的数据模型。

The Stats data model: Stats数据模型:

@Document
public class Stats {

  @JsonProperty
  private String type;

  @JsonProperty
  private int number;

  public Stats() {}

  /* ... */
}

The Profile data model: Profile数据模型:

@Document
public class Profiles {

  @NotNull
  @JsonProperty
  private String user;

  @NotNull
  @JsonProperty
  private String name;

  @JsonProperty
  private Map<String, String> attributes = new HashMap<>();

  public Stats() {}

  /* ... */
}

I found a solution, which was a combination of two problems: 我找到了一个解决方案,它是两个问题的组合:

The PropertyReferenceException was indeed caused because attributes is a Map<String, String> which means there is no schemes for Mongo. 实际上,造成PropertyReferenceException是因为attributesMap<String, String> ,这意味着没有适用于Mongo的方案。

The error message No property brand found for type String! Traversed path: Profile.attributes. 错误消息No property brand found for type String! Traversed path: Profile.attributes. No property brand found for type String! Traversed path: Profile.attributes. means that the Map object doesn't have a brand property in it. 表示Map对象中没有品牌属性。

In order to fix that without touching my orginal Profile class, I had to create a new custom class which would map the attributes to an attributes object having the properties I want to aggreate on like: 为了解决此问题而不接触原始的Profile类,我必须创建一个新的自定义类,该类将attributes映射到具有我要添加的attributes的attribute对象,例如:

public class StatsAttributes {

  @JsonProperty
  private String brand;

  @JsonProperty
  private String language;

  public StatsAttributes() {}

  /* ... */
}

Then I created a custom StatsProfile which would leverage my StatsAttributes and would be similar to the the original Profile object without modifying it. 然后,我创建了一个自定义StatsProfile ,它将利用我的StatsAttributes并且与原始的Profile对象相似,而无需对其进行修改。

@Document
public class StatsProfile {

  @JsonProperty
  private String user;

  @JsonProperty
  private StatsAttributes attributes;

  public StatsProfile() {}

  /* ... */
}

With that I made disapear my problem with the PropertyReferenceException using my new class StatsAggregation in the aggregation: 这样,我使用聚合中的新类StatsAggregation使PropertyReferenceException问题StatsAggregation了:

AggregationResults<Stats> groupResults 
     = mongoTemplate.aggregate(agg, StatsProfile.class, Stats.class);

However I would not get any results. 但是我不会得到任何结果。 It seems the query would not find any document in the database. 该查询似乎在数据库中找不到任何文档。 That's where I realied that production mongo objects had the field "_class: com.company.dao.model.Profile" which was tied to the Profile object. 那就是我意识到生产mongo对象具有与Profile对象相关联的字段"_class: com.company.dao.model.Profile"

After some research, for the new StatsProfile to work it would need to be a @TypeAlias("Profile") . 经过一番研究, StatsProfile新的StatsProfile起作用,它必须是@TypeAlias("Profile") After looking around, I found that I also needed to precise a collection name which would lead to: 环顾四周后,我发现还需要精确定义集合名称,这将导致:

@Document(collection = "profile")
@TypeAlias("Profile")
public class StatsProfile {

/* ... */
}

And with all that, finally it worked! 有了所有这些,终于奏效了!

I suppose that's not the prettiest solution, I wish I would not need to create a new Profile object and just consider the attributes as a StatsAttributes.class somehow in the mongoTemplate query. 我想这不是最漂亮的解决方案,我希望我不会需要创建一个新的配置文件对象,只考虑attributesStatsAttributes.class不知何故在mongoTemplate查询。 If anyone knows how to, please share 🙏 如果有人知道怎么做,请分享🙏

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring Data Mongo DB 在嵌套上应用@Indexed(unique = true) object - Spring Data Mongo DB applying @Indexed(unique = true) on nested object Spring Boot 1.5.8.Release-Spring Data Mongo PropertyReferenceException - Spring Boot 1.5.8.Release - Spring Data Mongo PropertyReferenceException Spring Data Mongo:如何按字段返回嵌套对象? - Spring Data Mongo: How to return nested object by its field? Spring Data MongDB 2.1.0中的PropertyReferenceException - PropertyReferenceException in spring data mongdb 2.1.0 如何在spring数据mongo db中进行这种聚合? - How to do this aggregation in spring data mongo db? 如何使用Spring Data Mongo DB对类进行建模,以存储具有不同字段和类型长度的嵌套JSON文档 - How to Model class using Spring Data Mongo DB to store nested JSON document with varying length of fields and type 使用 Spring Data MongoDB 获取 mongo DB 对象 - Fetching mongo DB object using Spring Data MongoDB 保存到Mongo DB时,如何配置Spring Data以使用对象的字符串版本? - How can I configure Spring Data to use the string version of an object when saving to Mongo DB? Spring Data JPA findAll与介于两者之间的表(PropertyReferenceException) - Spring Data JPA findAll with table in between (PropertyReferenceException) 如何在 spring mongo 中的两个单独的嵌套 object 之间进行排序 - How to sort between two separate nested object in spring mongo
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM