You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 22:07:06