繁体   English   中英

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

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

我正在springboot中创建一个新端点,该端点将对从mongo数据库中的聚合查询生成的用户返回简单的统计信息。 但是我得到了PropertyReferenceException 我已经阅读了关于它的多个stackoverflow问题,但没有找到解决该问题的方法。

我们有一个像这样的mongo数据方案:

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

该数据库充满了多个用户,我们希望使用Springboot汇总每个brand的用户统计信息。 attributes对象中可以有任意数量的属性。

这是我们正在做的汇总

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();

产生此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" }

但是,在运行简单的集成测试时,会出现以下错误:

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

据我了解,似乎由于attributesMap<String, String>所以可能存在一个示意图问题。 同时,我无法修改Profile对象。

聚合中是否缺少某些内容,或者我可以在Stats对象中更改的任何内容?

作为参考,以下是我们正在使用的用于JSON和jackson的数据模型。

Stats数据模型:

@Document
public class Stats {

  @JsonProperty
  private String type;

  @JsonProperty
  private int number;

  public Stats() {}

  /* ... */
}

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() {}

  /* ... */
}

我找到了一个解决方案,它是两个问题的组合:

实际上,造成PropertyReferenceException是因为attributesMap<String, String> ,这意味着没有适用于Mongo的方案。

错误消息No property brand found for type String! Traversed path: Profile.attributes. No property brand found for type String! Traversed path: Profile.attributes. 表示Map对象中没有品牌属性。

为了解决此问题而不接触原始的Profile类,我必须创建一个新的自定义类,该类将attributes映射到具有我要添加的attributes的attribute对象,例如:

public class StatsAttributes {

  @JsonProperty
  private String brand;

  @JsonProperty
  private String language;

  public StatsAttributes() {}

  /* ... */
}

然后,我创建了一个自定义StatsProfile ,它将利用我的StatsAttributes并且与原始的Profile对象相似,而无需对其进行修改。

@Document
public class StatsProfile {

  @JsonProperty
  private String user;

  @JsonProperty
  private StatsAttributes attributes;

  public StatsProfile() {}

  /* ... */
}

这样,我使用聚合中的新类StatsAggregation使PropertyReferenceException问题StatsAggregation了:

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

但是我不会得到任何结果。 该查询似乎在数据库中找不到任何文档。 那就是我意识到生产mongo对象具有与Profile对象相关联的字段"_class: com.company.dao.model.Profile"

经过一番研究, StatsProfile新的StatsProfile起作用,它必须是@TypeAlias("Profile") 环顾四周后,我发现还需要精确定义集合名称,这将导致:

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

/* ... */
}

有了所有这些,终于奏效了!

我想这不是最漂亮的解决方案,我希望我不会需要创建一个新的配置文件对象,只考虑attributesStatsAttributes.class不知何故在mongoTemplate查询。 如果有人知道怎么做,请分享🙏

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM