SpringData MongoDB内嵌数组聚合分页的名称重复问题
内嵌数组文档分页时客户名称重复问题
场景需求
需要对客户文档中的内嵌订单数组进行分页,筛选出所有状态为open的订单,按每页3条取第0页的结果。
Customer数据结构示例
{ "_id": ObjectId("cust-1"), "name": "John Doe", "orders": [ { "_id": ObjectId("order-1"), "status": "open" }, { "_id": ObjectId("order-2"), "status": "closed" } ] }, { "_id": ObjectId("cust-2"), "name": "Jane Doe", "orders": [ { "_id": ObjectId("order-3"), "status": "open" }, { "_id": ObjectId("order-4"), "status": "open" }, { "_id": ObjectId("order-5"), "status": "open" } ] }
预期分页结果(第0页,每页3条)
[ { "_id": ObjectId("cust-1"), "name": "John Doe", "orders": [ { "_id": ObjectId("order-1"), "status": "open" } ] }, { "_id": ObjectId("cust-2"), "name": "Jane Doe", "orders": [ { "_id": ObjectId("order-3"), "status": "open" }, { "_id": ObjectId("order-4"), "status": "open" } ] } ]
当前实现的问题
现有聚合逻辑中,GroupOperation使用push("name").as("name"),由于unwind操作会将每个订单拆分为单独的文档,同一个客户的每条订单记录都带有相同的name,push会把这些重复的name全部收集成数组,导致客户name字段出现重复值(比如Jane Doe的name变成["Jane Doe", "Jane Doe"])。
修正方案
分组时,针对客户name字段不要用push,改用first("name")或last("name")——因为同一个客户的name是唯一的,unwind后的所有记录name都一致,取第一条或最后一条即可得到正确的单个name值。
修正后的代码
// Operations UnwindOperation unwindOperation = Aggregation.unwind("orders"); CountOperation countOperation = Aggregation.count().as("total"); SkipOperation skipOperation = Aggregation.skip(pageable.getOffset()); LimitOperation limitOperation = Aggregation.limit(pageable.getPageSize()); // 修正分组逻辑:用first获取唯一的name,避免重复 GroupOperation groupOperation = Aggregation.group("_id") .push("orders").as("orders") .first("name").as("name"); // 替换push为first ProjectionOperation projectionOperation = Aggregation.project() .andInclude("orders") .andInclude("name"); // Facet FacetOperation facetOperation = Aggregation .facet( unwindOperation, countOperation) .as("metadata") .and( unwindOperation, skipOperation, limitOperation, groupOperation, projectionOperation) .as("data"); // Aggregation Aggregation aggregation = Aggregation.newAggregation( Aggregation.match(criteria), facetOperation ); AggregationResults<CustomerFacetResult> result = mongoTemplate.aggregate(aggregation, Customer.class, CustomerFacetResult.class); CustomerFacetResult fetchResult = result.getUniqueMappedResult();
内容的提问来源于stack exchange,提问作者Half_Duplex
相关产品推荐
相关产品推荐

