MongoDB查询未被编辑状态购物车引用的开放订单
需求说明
站点存在偶发同步故障,部分购买订单未关联到对应购物车,需要查询满足以下条件的订单文档:
- 属于
orders集合,status字段值为open - 文档的ObjectId类型
_id,未出现在carts集合中所有orderState为edit的文档的orders数组字段内
集合结构示例
orders集合文档示例
{ "_id" : ObjectId("5c5dac90c7f16568a5df67e5"), "shipment" : { "invoice" : "", "carrying" : "", "billingDate" : null, "shipmentDate" : null, "internalID" : "", "externalID" : "" }, "version" : NumberInt(0), "integrated" : false, "splited" : false, "totalValue" : NumberInt(0), "totalQty" : NumberInt(0), "mainSupplierOrder" : true, "id" : "", "shop" : ObjectId("5c5d88dcb60645517cf64990"), "supplier" : ObjectId("5c50bca84359b945410a2c2f"), "status" : "open", "config" : { "discount" : NumberInt(0), "paymentMethod" : "", "operation" : "100.01", "obs" : "", "conference" : false }, "products" : [], "history" : [], "createdDate" : ISODate("2019-02-08T16:21:36.644+0000"), "lastModifiedDate" : ISODate("2019-02-08T16:21:36.644+0000"), "lastModifiedBy" : "user.name", "__v" : NumberInt(0), "isOpen" : true }
carts集合文档示例
{ "_id" : ObjectId("5c5de236b47d8ddf670a21e8"), "calc" : ObjectId("62b40160e0f39d6cf5d9e3e9"), "shop" : ObjectId("5c5d88dcb60645517cf64969"), "createdBy" : "useremail@email.com.br", "lastModifiedBy" : "user.name", "orderState" : "edit", "orders" : [ ObjectId("5c5de26ab47d8ddf670a23b0"), ObjectId("62b1f84c2b9a7103926ab44c"), ObjectId("62b1f84c2b9a718e376ab449"), ObjectId("62b1f84c2b9a7130486ab444") ], "lastModifiedDate" : ISODate("2022-06-27T14:13:23.293+0000"), "createdDate" : ISODate("2019-02-08T20:10:30.460+0000"), "__v" : NumberInt(1) }
实现方案
提供两种可落地的查询方案,适配不同数据量场景:
方案1:聚合管道查询(推荐,全场景通用)
通过$lookup做关联匹配,单次查询即可得到结果,不受数据量大小限制,性能更稳定。
db.orders.aggregate([ // 提前筛选状态为open的订单,缩小后续匹配的数据范围 { $match: { status: "open" } }, // 关联carts集合,匹配edit状态购物车中包含当前订单ID的记录 { $lookup: { from: "carts", let: { currentOrderId: "$_id" }, pipeline: [ { $match: { orderState: "edit", $expr: { $in: ["$$currentOrderId", "$orders"] } } } ], as: "matchedCarts" } }, // 筛选没有匹配到对应购物车的订单,即为未同步的异常订单 { $match: { "matchedCarts.0": { $exists: false } } }, // 可选:移除查询结果中多余的matchedCarts字段 { $project: { matchedCarts: 0 } } ])
方案2:分步差集查询(适合中小数据量场景)
先提取所有已关联的订单ID,再查询不在关联集合内的异常订单,语法更简单易读。
- 先提取所有绑定在edit状态购物车上的订单ID,自动去重
const linkedOrderIds = db.carts.distinct("orders", { orderState: "edit" })
- 查询open状态、且ID不在已关联列表中的订单
db.orders.find({ status: "open", _id: { $nin: linkedOrderIds } })
注意:如果edit状态的购物车关联的总订单ID数据量超过16MB(MongoDB单文档最大限制),不要使用方案2,否则会触发参数超长报错,此时请使用方案1的聚合查询。
内容的提问来源于stack exchange,提问作者Henrique Gieseke
相关产品推荐
相关产品推荐

