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

MongoDB聚合中基于orderNo与articleCode的复合键关联失效

问题描述

需要通过MongoDB聚合操作,基于orderNo以及orderList和orderHistory两个集合中details字段下的articleCode进行复合键关联查询。

集合结构示例

orderList 集合:

{
  "orderNo": "0000004680",
  "details": [{
      "articleCode": "000000000910000130",
      "pgiStatus": " ",
      "fulfillmentStatus": "Y",
      "shortCloseStatus": "Y"
    },
    {
      "articleCode": "000000000910000131",
      "pgiStatus": " ",
      "shortCloseQty": "0",
      "fulfillmentStatus": "Y"
    }
  ]
}

orderHistory 集合:

{
  "orderNo": "0000004680",
  "orderHistoryStatus": "COM",
  "details": [{
    "shipmentStatus": "SHF",
    "articleCode": "000000000910000130",
    "billingDocNo": "0000123"
  }]
}

编写的聚合查询语句

let query = [{
    $match: {
      orderNo,
      "createdBy": userId
    }
  },
  {
    $unwind: "$details"
  },
  {
    $lookup: {
      from: "jed_order_history",
      let: {
        orderNo: "$orderNo",
        articleCode: "$details.articleCode"
      },
      pipeline: [{
        $match: {
          $expr: {
            $and: [{
                $eq: ["$orderNo", "$$orderNo"]
              },
              {
                $eq: ["$details.articleCode", "$$articleCode"]
              }
            ]
          }
        }
      }],
      as: "orderHistory"
    }
  },
  {
    $unwind: {
      path: "$orderHistory",
      preserveNullAndEmptyArrays: true
    }
  },
  {
    $lookup: {
      from: "jed_orderShipment",
      localField: "orderHistory.details.billingDocNo",
      foreignField: "billingNumber",
      as: "orderShipment"
    }
  },
  {
    $project: {
      orderNo: 1,
      createdAt: 1,
      paymentAccountingStatus: 1,
      orderListDetails: "$details",
      orderHistory: {
        $ifNull: ["$orderHistory", {}]
      },
      orderShipment: {
        $ifNull: [{
          $arrayElemAt: ["$orderShipment", 0]
        }, {}]
      }
    }
  }
];

问题现象

加入{ $eq: ["$details.articleCode", "$$articleCode"] }条件后,查询结果中的orderHistory和orderShipment均为空对象,但实际存在匹配数据;移除该条件后可正常获取预期数据,但业务要求必须基于orderNo和details.articleCode进行复合键关联。


解决方案

问题核心:orderHistory集合中的details是数组字段,直接用$details.articleCode与单个字符串值$$articleCode做相等比较时,数组和字符串永远不匹配,导致lookup无结果。

修正后的聚合查询

以下是两种可行的修正方式,均能实现orderNo+details.articleCode的复合键关联:

方式一:使用$in匹配数组中的articleCode

let query = [{
    $match: {
      orderNo,
      "createdBy": userId
    }
  },
  {
    $unwind: "$details"
  },
  {
    $lookup: {
      from: "jed_order_history",
      let: {
        orderNo: "$orderNo",
        articleCode: "$details.articleCode"
      },
      pipeline: [{
        $match: {
          $expr: {
            $and: [
              { $eq: ["$orderNo", "$$orderNo"] },
              // 提取orderHistory.details中的所有articleCode组成数组,判断目标值是否在其中
              { $in: ["$$articleCode", { $map: { input: "$details", as: "d", in: "$$d.articleCode" } }] }
            ]
          }
        }
      }],
      as: "orderHistory"
    }
  },
  {
    $unwind: {
      path: "$orderHistory",
      preserveNullAndEmptyArrays: true
    }
  },
  {
    $lookup: {
      from: "jed_orderShipment",
      localField: "orderHistory.details.billingDocNo",
      foreignField: "billingNumber",
      as: "orderShipment"
    }
  },
  {
    $project: {
      orderNo: 1,
      createdAt: 1,
      paymentAccountingStatus: 1,
      orderListDetails: "$details",
      orderHistory: {
        $ifNull: ["$orderHistory", {}]
      },
      orderShipment: {
        $ifNull: [{
          $arrayElemAt: ["$orderShipment", 0]
        }, {}]
      }
    }
  }
];

方式二:使用$anyElementTrue判断数组中存在匹配元素

let query = [{
    $match: {
      orderNo,
      "createdBy": userId
    }
  },
  {
    $unwind: "$details"
  },
  {
    $lookup: {
      from: "jed_order_history",
      let: {
        orderNo: "$orderNo",
        articleCode: "$details.articleCode"
      },
      pipeline: [{
        $match: {
          $expr: {
            $and: [
              { $eq: ["$orderNo", "$$orderNo"] },
              // 遍历orderHistory.details数组,判断是否有元素的articleCode匹配目标值
              {
                $anyElementTrue: {
                  $map: {
                    input: "$details",
                    as: "histDetail",
                    in: { $eq: ["$$histDetail.articleCode", "$$articleCode"] }
                  }
                }
              }
            ]
          }
        }
      }],
      as: "orderHistory"
    }
  },
  {
    $unwind: {
      path: "$orderHistory",
      preserveNullAndEmptyArrays: true
    }
  },
  {
    $lookup: {
      from: "jed_orderShipment",
      localField: "orderHistory.details.billingDocNo",
      foreignField: "billingNumber",
      as: "orderShipment"
    }
  },
  {
    $project: {
      orderNo: 1,
      createdAt: 1,
      paymentAccountingStatus: 1,
      orderListDetails: "$details",
      orderHistory: {
        $ifNull: ["$orderHistory", {}]
      },
      orderShipment: {
        $ifNull: [{
          $arrayElemAt: ["$orderShipment", 0]
        }, {}]
      }
    }
  }
];

可选优化:精准匹配单个明细项

如果需要仅保留orderHistory中匹配的details项(而非整个数组),可以在lookup的pipeline中先拆分数组再匹配,最后重组结构:

let query = [{
    $match: {
      orderNo,
      "createdBy": userId
    }
  },
  {
    $unwind: "$details"
  },
  {
    $lookup: {
      from: "jed_order_history",
      let: {
        orderNo: "$orderNo",
        articleCode: "$details.articleCode"
      },
      pipeline: [
        { $match: { $expr: { $eq: ["$orderNo", "$$orderNo"] } } },
        { $unwind: "$details" },
        { $match: { $expr: { $eq: ["$details.articleCode", "$$articleCode"] } } },
        // 重组orderHistory文档结构
        {
          $group: {
            _id: "$_id",
            orderNo: { $first: "$orderNo" },
            orderHistoryStatus: { $first: "$orderHistoryStatus" },
            details: { $push: "$details" }
          }
        }
      ],
      as: "orderHistory"
    }
  },
  {
    $unwind: {
      path: "$orderHistory",
      preserveNullAndEmptyArrays: true
    }
  },
  {
    $lookup: {
      from: "jed_orderShipment",
      localField: "orderHistory.details.billingDocNo",
      foreignField: "billingNumber",
      as: "orderShipment"
    }
  },
  {
    $project: {
      orderNo: 1,
      createdAt: 1,
      paymentAccountingStatus: 1,
      orderListDetails: "$details",
      orderHistory: {
        $ifNull: ["$orderHistory", {}]
      },
      orderShipment: {
        $ifNull: [{
          $arrayElemAt: ["$orderShipment", 0]
        }, {}]
      }
    }
  }
];

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 07:55:54