如何用Spring Data MongoDB实现含嵌套字段的Group聚合查询?
问题描述
需要将指定的MongoDB原生聚合查询转换为Spring Data MongoDB代码,要求返回结果的_id中包含嵌套的date对象(含年、月、日字段)。
集合数据结构
{ date: ISODate("2022-12-11T01:13:00.000Z"), metadata: { homeId: '51b87ea3d846f450141ae58z', nodeId: '51b87ea3d846f450141ae58z' }, value: 42, _id: ObjectId("63b583e30c1e523313b64ed5") }
目标MongoDB原生查询
db.consumptions.aggregate([ { $match : {"metadata.nodeId": "51b87ea3d846f450141ae58z"} }, { $project: { date: { $dateToParts: { date: "$date"} }, value: 1 } }, { $group: { _id: { date: { year: "$date.year", month: "$date.month", day: "$date.day" } }, cumulValue: { $sum: "$value"} } }, { $sort : { "_id.date": -1} } ])
预期返回结果
[ { _id: { date: { year: 2022, month: 12, day: 11 } }, cumulValue: 42 } ]
尝试的Spring Data MongoDB代码(不符合预期)
MatchOperation matchOperation = Aggregation.match( new Criteria().andOperator(Criteria.where("metadata.nodeId").is(nodeId)) ); // projection Operation ProjectionOperation projectionOperation = project("value") .and(DateOperators.dateOf("date").toParts()).as("date"); // group Operation GroupOperation groupOperation = Aggregation.group( "date.year", "date.month", "date.day") .sum("value").as("cumulativeValue"); // Sort Operation SortOperation sortOperation = sort(pageRequest.getSort()); Aggregation aggregation = Aggregation.newAggregation( matchOperation, projectionOperation, groupOperation, sortOperation);
当前不符合预期的结果
{ _id: { year: 2022, month: 11, day: 11 }, cumulValue: 284 }
解决方案
要实现嵌套的date结构在_id中,需在GroupOperation里手动构建嵌套字段结构,而非直接传入字段路径。具体代码如下:
// Match操作保持不变 MatchOperation matchOperation = Aggregation.match( Criteria.where("metadata.nodeId").is(nodeId) ); // Projection操作保持不变,生成包含year/month/day的date对象 ProjectionOperation projectionOperation = project("value") .and(DateOperators.dateOf("date").toParts()).as("date"); // 构建嵌套的_id结构:_id.date.year/month/day GroupOperation groupOperation = Aggregation.group( Fields.from( Fields.field("date.year", "date.year"), Fields.field("date.month", "date.month"), Fields.field("date.day", "date.day") ) ).sum("value").as("cumulValue"); // 按_id.date降序排序,与原生查询逻辑一致 SortOperation sortOperation = Sort.by(Sort.Direction.DESC, "_id.date"); // 组装聚合操作 Aggregation aggregation = Aggregation.newAggregation( matchOperation, projectionOperation, groupOperation, sortOperation );
关键说明
- 原代码中
group("date.year", "date.month", "date.day")会将三个字段平放在_id下,而使用Fields.from()并指定嵌套字段路径(如date.year),可让MongoDB生成_id.date的嵌套结构。 - 排序部分直接指定
"_id.date"即可实现与原生查询一致的降序逻辑。
内容的提问来源于stack exchange,提问作者MRA
相关产品推荐
相关产品推荐

