【问题标题】:Mongodb combine aggregate queriesMongodb 结合聚合查询
【发布时间】:2025-12-24 09:45:10
【问题描述】:

我在 MongoDB 中有以下集合

个人资料集合

> db.Profile.find()
{ "_id" : ObjectId("5ec62ccb8897af3841a46d46"), "u" : "Test User", "is_del": false }

商店收藏

> db.Store.find()
{ "_id" : ObjectId("5eaa939aa709c30ff4703ffd"), "id" : "5ec62ccb8897af3841a46d46",  "a" : { "ci": "Test City", "st": "Test State" }, "ip" : false }, "op" : [ ], "b" : [ "normal" ], "is_del": false}

物品收藏

> db.Item.find()
{ "_id" : ObjectId("5ea98a25f1246b53a46b9e10"), "sid" : "5eaa939aa709c30ff4703ffd", "n" : "sample", "is_del": false}

这些集合之间的关系定义如下:

  1. Profile -> Store:是1:n 关系。 Store 中的 id 字段与 Profile 中的 _id 字段相关。
  2. Store -> Item:也是1:n关系。 Item 中的 sid 字段与 Store 中的 _id 字段相关。

现在,我需要编写一个查询来查找所有配置文件商店以及每个商店的 Item 计数。必须排除 is_deltrue 的文档。

我正在尝试以下方式:

  1. 查询 1 以查找每个商店的商品计数。
  2. 查询 2 以查找每个配置文件的商店。

然后在应用程序逻辑中使用这两个结果来产生组合输出。

我有如下查询1:

db.Item.aggregate({$group: {_id: "$sid", count:{$sum:1}}})

查询2如下:

db.Profile.aggregate([{ "$addFields": { "pid": { "$toString": "$_id" }}},   { "$lookup": {"from": "Store","localField": "pid","foreignField": "id",  "as": "stores"}}])

在查询中,is_del 也丢失了。有没有更简单的方法可以在单个查询中执行所有这些操作?如果是这样,对可扩展性有何影响?

【问题讨论】:

  • 您在Store集合中的文档结构有点奇怪,"ip": false后面应该有一个右大括号吗?
  • 你为什么不发布一些所有集合的样本数据?
  • @thammada.ts 感谢您的指出。我认为 Ashh 纠正了这一点。
  • @varman:样本数据在那里。如果您需要更多信息,请告诉我。

标签: mongodb mongodb-query


【解决方案1】:

您可以使用 MongoDB v3.6 中提供的不相关子查询

db.Profile.aggregate([
  {
    $match: { is_del: false }
  },
  {
    $lookup: {
      from: "Store",
      as: "stores",
      let: {
        pid: { $toString: "$_id" }
      },
      pipeline: [
        {
          $match: {
            is_del: false,
            $expr: { $eq: ["$$pid", "$id"] }
          }
        },
        {
          $lookup: {
            from: "Item",
            as: "items",
            let: {
              sid: { $toString: "$_id" }
            },
            pipeline: [
              {
                $match: {
                  is_del: false,
                  $expr: { $eq: ["$$sid", "$sid"] }
                }
              },
              {
                $count: "count"
              }
            ]
          }
        },
        {
          $unwind: "$items"
        }
      ]
    }
  }
])

Mongo Playground

为了提高性能,我建议您将参考 ID 存储为 ObjectId,这样您就不必在每个步骤中进行转换。

【讨论】: