如何在 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"}}}
])

如您所见,这会执行以下操作:

  1. 仅匹配具有指定 ID 的特定文档
  2. 将嵌套字段向下投影到基本级别字段(并有效地从管道中过滤掉所有其他字段,但仍保留 ID)
  3. 展开我们投影到管道中各个文档的 $versions 字段的数组元素
  4. 找到每个 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)