[英]Spring Data Mongo DB applying @Indexed(unique = true) on nested object
[英]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.
据我了解,似乎由于attributes
是Map<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
是因为attributes
是Map<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 {
/* ... */
}
有了所有这些,终于奏效了!
我想这不是最漂亮的解决方案,我希望我不会需要创建一个新的配置文件对象,只考虑
attributes
的StatsAttributes.class
不知何故在mongoTemplate查询。 如果有人知道怎么做,请分享🙏
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.