spring-data-mongodb 上的 TopN 聚合

问题描述 投票:0回答:3

我正在尝试使用 spring-data-mongo 实现带有 TopN 聚合运算符的分组,但我不知道如何做到这一点。

从 MongoDB 的 POV 中我知道我想要什么。是这样的:

[ { 
    $match: { 
      field000: { $regex: ".*MATCHTHIS.*" }, 
      created: { $lte: new Date("2030-05-25T00:00:00.000+00:00" ) } 
    }, 
  }, 
  { 
     $group: { 
       _id: "$field001", 
       field001s: { 
         $topN: { 
           output: ["$field002", "$created"], 
           sortBy: { created: -1, }, 
           n: 1, 
         }
       }
     }
    }]

含义...对于已经通过$match子句过滤的文档集;按 field001 分组,按创建的 desc 对每个存储桶进行排序,然后选择顶部 (1)。因此,每个组类别最近创建的文档。

我发现将其转换为 spring-data-mongo 时存在问题

mongodb spring-data-mongodb
3个回答
1
投票

使用

MongoRepository
,您可以使用
@Aggregate
注释指定管道。像这样的东西:

@Aggregation(pipeline = {"{ $match: { field000: { $regex: '?0' }, created: { $lte: '?1' } },}, { $group: { _id: '$field001', field001s: { $topN: { output: ['$field002', '$created'], sortBy: { created: -1, }, n: 1}}}}"})
Object filterAndGroup(String regex, ZonedDateTime created);

请注意,我已参数化搜索正则表达式和日期值。请相应地更新它以及函数的返回类型。使用

MongoTemplate
,您可以尝试按照这些思路进行操作。

MatchOperation matchStage = Aggregation.match(
   new Criteria("field000").regex(".*MATCHTHIS.*")
     .and(new Criteria("created").lte(YOUR_JAVA_DATE_OBJECT))
);
ProjectionOperation projectStage = Aggregation.project("field002", "created", "field001");
SortOperation sortByCreatedDesc = sort(Sort.by(Direction.DESC, "created"));
GroupOperation groupStage = Aggregation.group("field001").first("$$ROOT").as("field001s");

Aggregation aggregation = newAggregation(
  matchStage, projectStage, sortByCreatedDesc, groupStage);
AggregationResults<XYZModel> result = mongoTemplate.aggregate(
  aggregation, "collectionName", XYZModel.class);

请注意,我为

Projection
Sorting
添加了两个新阶段,因为
$topN
尚未受Spring Data MongoDB支持,所以我投影必要的字段,然后按
created
排序,然后然后对文档进行分组并选择每组中的第一个。

注意:答案没有经过我测试,所以你必须尝试并调整它。


0
投票

经过大量研究,我意识到这个问题在 spring-data-mongodb 最新版本上可能很容易解决,因为实现了“topN”聚合运算符。然而,就我而言,升级堆栈以支持该版本并不是一个选择。

另一方面,如果您使用存储库,那么 @Charchit Kapoor 解决方案可能是最好的解决方案。

如果你想坚持使用 mongo 模板,可以这样做:

    AggregateIterable<Document> result = mongoOps.getCollection(COLLECTION_NAME).aggregate(Arrays.asList(new Document("$match",
        new Document("field000",
          new Document("$regex", ".*REGEXP_FIELD_000.*"))
          .append("created",
            new Document("$lte",
              new java.util.Date(1685318400000L)))),
      new Document("$group",
        new Document("_id", "$field001")
          .append("Field0001s",
            new Document("$topN",
              new Document("output", Arrays.asList("$field002", "$created"))
                .append("sortBy",
                  new Document("created", -1L))
                .append("n", 1L))))));

您可以将其分成不同的方法以获得更好的可读性。


0
投票

如果你可以使用

mongoTemplate
,它有这个方法来限制排序和其他聚合中的结果
Aggregation.limit(N)

看这个例子:

newAggregation(
  Aggregation.group(
     Fields.from(
         Fields.field("field1", "pspType"), 
         Fields.field("field2", "createdDate")
                        )),
    Aggregation.sort(Sort.Direction.DESC, "field1"),
    Aggregation.limit(2)
)  
© www.soinside.com 2019 - 2024. All rights reserved.