MongoDB: 一对多关系的最优连接

MongoDB: Optimal joining of one to many relationship

这里是订单和产品的假设案例。

  1. 'products' collection
[
  {
    "_id": "61c53eb76eb2dc65de621bd0",
    "name": "Product 1",
    "price": 80
  },
  {
    "_id": "61c53efca0a306c3f1160754",
    "name": "Product 2",
    "price": 10
  },
  ... // truncated
]
  1. 'orders' collection:
[
  {
    "_id": "61c53fb7dca0579de038cea8", // order id

    "products": [
      {
        "_id": "61c53eb76eb2dc65de621bd0", // references products._id
        "quantity": 1
      },
      {
        "_id": "61c53efca0a306c3f1160754",
        "quantity": 2
      },
    ]
  }
]

如您所见,一个订单拥有一个产品 ID 列表。当我提取订单的详细信息时,我还需要像这样组合的产品详细信息:

{
    _id: ObjectId("61c53fb7dca0579de038cea8"),
    products: [
        {
            _id: ObjectId("61c53eb76eb2dc65de621bd0"),
            quantity: 1,
            name: 'Product 1',
            price: 80
        },
        {
            _id: ObjectId("61c53efca0a306c3f1160754"),
            quantity: 2,
            name: 'Product 2',
            price: 10
        },
        ... // truncated
    ]
}

这是我想出的聚合管道:

db.orders.aggregate([

  {
    $match: {_id: ObjectId('61c53fb7dca0579de038cea8')}
  },

  {
    $unwind: {
      path: "$products"
    }
  },

  {
    $lookup: {
      from: 'products',
      localField: 'products._id',
      foreignField: '_id',
      as: 'productDetail'
    }
  },

  {
    $unwind: {
      path: "$productDetail"
    }
  },

 {
   $group: {
     _id: "$_id",
     products: {
       $push: {$mergeObjects: ["$products", "$productDetail"]}
     }
   }
 }
])

考虑到数据的组织方式,我怀疑管道阶段是否是最佳的并且可以做得更好(减少阶段数量的可能性等)。有什么建议吗?

正如评论中已经提到的那样,设计很差。你可以避免多个$unwind$group,通常这样性能应该更好:

db.orders.aggregate([
  { $match: { _id: "61c53fb7dca0579de038cea8" } },
  {
    $lookup: {
      from: "products",
      localField: "products._id",
      foreignField: "_id",
      as: "productDetail"
    }
  },
  {
    $project: {
      products: {
        $map: {
          input: "$products",
          as: "product",
          in: {
            $mergeObjects: [
              "$$product",
              {
                $first: {
                  $filter: {
                    input: "$productDetail",
                    cond: { $eq: [ "$$this._id", "$$product._id" ] }
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
])

Mongo Playground