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

MongoDB聚合函数问题:仅返回指定父文档关联的参考数据

MongoDB聚合查询仅返回指定父文档关联参考数据的解决方法

当前聚合查询会返回REF_123和REF_456两个参考数据,但我们只需要返回分页后得到的OF_Code父文档关联的REF_123。问题根源在于原查询先对所有匹配$match条件的父文档执行了$lookup,再做分页筛选,导致拉取了所有关联的参考数据。


文档结构

ParentDocument

[
  {
    "code": "OF_Code",
    "version": "1",
    "createdBy": "abc",
    "attributes": {
      "associatedProducts": [
        {
          "bundleProducts": [
            {
              "products": [
                {
                  "key": "REF_123"
                }
              ]
            }
          ]
        }
      ]
    }
  },
  {
    "code": "OF_Code2",
    "version": "1",
    "createdBy": "abc",
    "attributes": {
      "associatedProducts": [
        {
          "bundleProducts": [
            {
              "products": [
                {
                  "key": "REF_123"
                }
              ]
            }
          ]
        }
      ]
    }
  },
  {
    "code": "OF_Code3",
    "version": "1",
    "createdBy": "abc",
    "attributes": {
      "associatedProducts": [
        {
          "bundleProducts": [
            {
              "products": [
                {
                  "key": "REF_456"
                }
              ]
            }
          ]
        }
      ]
    }
  }
]

ReferencedDocument

[
  {
    "code": "REF_123",
    "status": "live"
  },
  {
    "code": "REF_456",
    "status": "live"
  },
  {
    "code": "REF_789",
    "status": "live"
  }
]

原查询语句

db.parents.aggregate([
  {
    "$match": {
      "code": {
        "$in": [
          "OF_Code",
          "OF_Code2",
          "OF_Code3"
        ]
      }
    }
  },
  {
    "$lookup": {
      "from": "reference",
      "localField": "attributes.associatedProducts.bundleProducts.products.key",
      "foreignField": "code",
      "as": "refs",
      "pipeline": [
        {
          "$project": {
            "_id": 0
          }
        }
      ]
    }
  },
  {
    "$facet": {
      "pagination": [
        {
          "$count": "count"
        }
      ],
      "Parent": [
        {
          "$skip": 0
        },
        {
          "$limit": 1
        }
      ],
      "Reference": [
        {
          "$unwind": "$refs"
        },
        {
          "$group": {
            "_id": null,
            "Reference": {
              "$addToSet": "$refs"
            }
          }
        },
        {
          "$unwind": "$Reference"
        },
        {
          $replaceWith: "$Reference"
        }
      ]
    }
  },
  {
    "$unset": "_id"
  },
  {
    "$unset": "Parent.refs"
  }
])

当前返回结果

"Reference": [
  {
    "code": "REF_123",
    "status": "live"
  },
  {
    "code": "REF_456",
    "status": "live"
  }
]

期望返回结果

"Reference": [
  {
    "code": "REF_123",
    "status": "live"
  }
]

解决方法

核心思路是先筛选出分页后的目标父文档,再针对该文档执行关联查询,避免拉取所有父文档的关联数据。以下是优化后的查询:

db.parents.aggregate([
  {
    "$match": {
      "code": { "$in": ["OF_Code", "OF_Code2", "OF_Code3"] }
    }
  },
  // 先执行分页,筛选出目标父文档
  { "$skip": 0 },
  { "$limit": 1 },
  // 提取当前父文档关联的所有产品key
  {
    "$addFields": {
      "productKeys": {
        "$reduce": {
          "input": "$attributes.associatedProducts",
          "initialValue": [],
          "in": {
            "$concatArrays": [
              "$$value",
              {
                "$reduce": {
                  "input": "$$this.bundleProducts",
                  "initialValue": [],
                  "in": {
                    "$concatArrays": [
                      "$$value",
                      { "$map": { "input": "$$this.products", "as": "p", "in": "$$p.key" } }
                    ]
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
  {
    "$facet": {
      "pagination": [
        { "$count": "count" }
      ],
      "Parent": [
        // 移除不需要的字段,保持原有结构
        { "$unset": ["productKeys"] }
      ],
      "Reference": [
        // 仅用当前父文档的productKeys关联参考数据
        {
          "$lookup": {
            "from": "reference",
            "localField": "productKeys",
            "foreignField": "code",
            "as": "refs",
            "pipeline": [
              { "$project": { "_id": 0 } }
            ]
          }
        },
        { "$unwind": "$refs" },
        { "$replaceWith": "$refs" }
      ]
    }
  },
  { "$unset": "_id" }
])

修改说明

  1. 调整执行顺序:先通过$skip和$limit筛选出目标父文档,避免对所有匹配$match的文档执行关联操作
  2. 提取关联key:用$reduce和$concatArrays嵌套提取父文档中所有关联的产品key,确保只关联当前文档的参考数据
  3. 分面处理:在facet中分别处理父文档输出和参考数据输出,保证结构与原查询一致

内容的提问来源于stack exchange,提问作者Hero

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 15:01:01