如何在 Spring 中编写此 Mongo 聚合查询?
How do I write this Mongo aggregation query in Spring?
我在 MongoDB 中有一个聚合查询,当我在 运行 中直接在 shell 中时它可以工作。这是 shell 查询:
db.MyCollection.aggregate([
{$match: {_id: {$in: ['A', 'B', 'C']}}},
{$project: {"versions": "$nested.field.version"}},
{$unwind: "$versions"},
{$group: {_id: "$_id", "maxVersion": {$max: "$versions"}}}
])
如您所见,这会执行以下操作:
- 仅匹配具有指定 ID 的特定文档
- 将嵌套字段向下投影到基本级别字段(并有效地从管道中过滤掉所有其他字段,但仍保留 ID)
- 展开我们投影到管道中各个文档的 $versions 字段的数组元素
- 找到每个 ID 的那些 $versions 的最大值
正如我所说,上面的查询已经有效。我的问题是如何将其转换为 Spring MongoDB 语法。这是我的第一次尝试,它 没有 工作:
Aggregation aggregation = newAggregation(
match(Criteria.where("_id").in(listOfIds))
,project().and("versions").nested(bind("versions", "nested.field.version"))
,unwind("versions")
,group("_id").max("versions").as("maxVersion")
);
当我尝试 运行 调试模式下的代码时,我可以看到我实际上在 newAggregation 上得到一个 IllegalArgumentException 说它无法计算。如果我注释掉带有 $group 子句的行,那么我可以看到聚合变量的 toString() 表示,这揭示了 $project 子句的问题:
{
"aggregate" : "__collection__" ,
"pipeline" : [
{ "$match" : { "_id" : { "$in" : [ "A" , "B" , "C"]}}} ,
{ "$project" : { "versions" : { "versions" : "$nested.field.version"}}} ,
{ "$unwind" : "$versions"}
]
}
显然这与我的意图不符,所以我的语法不正确。但老实说,我发现 Spring MongoOps 语法不是很直观,而且他们的文档也不是很好。
如果不首先包含对 and()
的调用,我看不出有任何方法可以调用 nested()
方法。我认为这是主要问题,因为它在那里加倍了嵌套。这里有 Spring MongoOps 大侠可以帮助我正确编写等效的 Java 代码吗?
编辑: 这是我正在使用的集合的快照:
嵌套字段上的 $project
pipeline is not necessary since you can still do an $unwind
,因此此聚合管道可以产生与当前相同的结果:
db.MyCollection.aggregate([
{
"$match": {
"_id": { "$in": ['A', 'B', 'C'] }
}
},
{ "$unwind": "$nested.field" },
{
"$group": {
"_id": "$_id",
"maxVersion": { "$max": "$nested.field.version" }
}
}
])
Spring数据MongoDB聚合等价:
Aggregation agg = newAggregation(
match(Criteria.where("_id").in(ids)),
unwind("nested.field"),
group("_id").max("nested.field.version").as("maxVersion")
);
回到您当前的聚合,您需要 $unwind
nested.field
数组,而不是 nested.field.version
字段,因为那是一个字符串,不是数组:
db.MyCollection.aggregate([
{$match: {_id: {$in: ['A', 'B', 'C']}}},
{$project: {"fields": "$nested.field"}},
{$unwind: "$fields"},
{$group: {_id: "$_id", "maxVersion": {$max: "$fields.version"}}}
])
Sprind Data MongoDB 等效项如下所示:
Aggregation agg = newAggregation(
match(Criteria.where("_id").in(ids)),
project().and("nested.field").as("fields")
unwind("fields"),
group("_id").max("fields.version").as("maxVersion")
);
在修复下划线错误之前使用 map reduce 方式。
喜欢 :
GroupBy groupBy = GroupBy.key("user_id")
.initialDocument("{ total : 0, used : 0 }")
.reduceFunction("function( curr, result ){ result.total++; if(curr.status == 1) {result.used++;} result.userID = curr.user_id;");
GroupByResults<YourResult> yourResultInfo =
mongoTemplate.group(Criteria.where("user_id").in(user_ids),
"your_collection_name", groupBy, YourResult.class);
class YourResult{
private String userID;
private Long total = 0l;
private Long used = 0l;
// getter and setter`enter code here
}
Spring 使用 _ 作为数组的通配符,并在聚合操作中执行字段引用验证时拆分 snake_case 字段。
为避免验证,您可以使用以下 MongoTemplate 方法,该方法执行聚合,无需字段转换和验证。
public <O> AggregationResults<O> aggregate(Aggregation aggregation, String collectionName, Class<O> outputType)
我在 MongoDB 中有一个聚合查询,当我在 运行 中直接在 shell 中时它可以工作。这是 shell 查询:
db.MyCollection.aggregate([
{$match: {_id: {$in: ['A', 'B', 'C']}}},
{$project: {"versions": "$nested.field.version"}},
{$unwind: "$versions"},
{$group: {_id: "$_id", "maxVersion": {$max: "$versions"}}}
])
如您所见,这会执行以下操作:
- 仅匹配具有指定 ID 的特定文档
- 将嵌套字段向下投影到基本级别字段(并有效地从管道中过滤掉所有其他字段,但仍保留 ID)
- 展开我们投影到管道中各个文档的 $versions 字段的数组元素
- 找到每个 ID 的那些 $versions 的最大值
正如我所说,上面的查询已经有效。我的问题是如何将其转换为 Spring MongoDB 语法。这是我的第一次尝试,它 没有 工作:
Aggregation aggregation = newAggregation(
match(Criteria.where("_id").in(listOfIds))
,project().and("versions").nested(bind("versions", "nested.field.version"))
,unwind("versions")
,group("_id").max("versions").as("maxVersion")
);
当我尝试 运行 调试模式下的代码时,我可以看到我实际上在 newAggregation 上得到一个 IllegalArgumentException 说它无法计算。如果我注释掉带有 $group 子句的行,那么我可以看到聚合变量的 toString() 表示,这揭示了 $project 子句的问题:
{
"aggregate" : "__collection__" ,
"pipeline" : [
{ "$match" : { "_id" : { "$in" : [ "A" , "B" , "C"]}}} ,
{ "$project" : { "versions" : { "versions" : "$nested.field.version"}}} ,
{ "$unwind" : "$versions"}
]
}
显然这与我的意图不符,所以我的语法不正确。但老实说,我发现 Spring MongoOps 语法不是很直观,而且他们的文档也不是很好。
如果不首先包含对 and()
的调用,我看不出有任何方法可以调用 nested()
方法。我认为这是主要问题,因为它在那里加倍了嵌套。这里有 Spring MongoOps 大侠可以帮助我正确编写等效的 Java 代码吗?
编辑: 这是我正在使用的集合的快照:
嵌套字段上的 $project
pipeline is not necessary since you can still do an $unwind
,因此此聚合管道可以产生与当前相同的结果:
db.MyCollection.aggregate([
{
"$match": {
"_id": { "$in": ['A', 'B', 'C'] }
}
},
{ "$unwind": "$nested.field" },
{
"$group": {
"_id": "$_id",
"maxVersion": { "$max": "$nested.field.version" }
}
}
])
Spring数据MongoDB聚合等价:
Aggregation agg = newAggregation(
match(Criteria.where("_id").in(ids)),
unwind("nested.field"),
group("_id").max("nested.field.version").as("maxVersion")
);
回到您当前的聚合,您需要 $unwind
nested.field
数组,而不是 nested.field.version
字段,因为那是一个字符串,不是数组:
db.MyCollection.aggregate([
{$match: {_id: {$in: ['A', 'B', 'C']}}},
{$project: {"fields": "$nested.field"}},
{$unwind: "$fields"},
{$group: {_id: "$_id", "maxVersion": {$max: "$fields.version"}}}
])
Sprind Data MongoDB 等效项如下所示:
Aggregation agg = newAggregation(
match(Criteria.where("_id").in(ids)),
project().and("nested.field").as("fields")
unwind("fields"),
group("_id").max("fields.version").as("maxVersion")
);
在修复下划线错误之前使用 map reduce 方式。 喜欢 :
GroupBy groupBy = GroupBy.key("user_id")
.initialDocument("{ total : 0, used : 0 }")
.reduceFunction("function( curr, result ){ result.total++; if(curr.status == 1) {result.used++;} result.userID = curr.user_id;");
GroupByResults<YourResult> yourResultInfo =
mongoTemplate.group(Criteria.where("user_id").in(user_ids),
"your_collection_name", groupBy, YourResult.class);
class YourResult{
private String userID;
private Long total = 0l;
private Long used = 0l;
// getter and setter`enter code here
}
Spring 使用 _ 作为数组的通配符,并在聚合操作中执行字段引用验证时拆分 snake_case 字段。
为避免验证,您可以使用以下 MongoTemplate 方法,该方法执行聚合,无需字段转换和验证。
public <O> AggregationResults<O> aggregate(Aggregation aggregation, String collectionName, Class<O> outputType)