我正在尝试使用 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 时存在问题
使用
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
排序,然后然后对文档进行分组并选择每组中的第一个。
注意:答案没有经过我测试,所以你必须尝试并调整它。
经过大量研究,我意识到这个问题在 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))))));
您可以将其分成不同的方法以获得更好的可读性。
如果你可以使用
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)
)