【问题标题】:MongoDB: finding matched elements in the third level embed documentsMongoDB:在第三级嵌入文档中查找匹配的元素
【发布时间】:2021-01-05 15:51:47
【问题描述】:

我是 MongoDB 的新手。我有一个典型的用例。这是我的单文档 JSON 结构。

{
    "category":"cat_1",
    "_id": "id1",
    "levels":[
        {
            "id":"l1",
            "orders":[
                {
                    "id":"o1",
                    "screens":[
                        {
                            "id":"l1o1s1",
                            "name":"screen1"
                        },
                        {
                            "id": "l1o1s2",
                            "name": "screen2"
                        }
                    ]
                },
                {
                    "id": "o2",
                    "screens": [
                        {
                            "id": "l1o2s1",
                            "name": "screen3"
                        },
                        {
                            "id": "l1o2s2",
                            "name": "screen4"
                        }
                    ]
                }
            ]
        },
        {
            "id": "l2",
            "orders": [
                {
                    "id": "o1",
                    "screens": [
                        {
                            "id": "l2o1s1",
                            "name": "screen5"
                        },
                        {
                            "id": "l2o1s2",
                            "name": "screen6"
                        }
                    ]
                },
                {
                    "id": "o2",
                    "screens": [
                        {
                            "id": "l2o2s1",
                            "name": "screen7"
                        },
                        {
                            "id": "l2o2s2",
                            "name": "screen8"
                        }
                    ]
                }
            ]
        }
    ]
}

在这里,我想获取仅给定屏幕 ID 的数据。例如,如果["l1o1s1","l1o2s2","l2o1s1","l2o2s1"] 是我应该在文档中找到的屏幕 ID 列表, 然后我想要如下结果(它应该返回仅在输入中给出的屏幕 ID)

 {
    "category":"cat_1",
    "_id": "id1",
    "levels":[
        {
            "id":"l1",
            "orders":[
                {
                    "id":"o1",
                    "screens":[
                        {
                            "id":"l1o1s1",
                            "name":"screen1"
                        }
                    ]
                },
                {
                    "id": "o2",
                    "screens": [
                        {
                            "id": "l1o2s2",
                            "name": "screen4"
                        }
                    ]
                }
            ]
        },
        {
            "id": "l2",
            "orders": [
                {
                    "id": "o1",
                    "screens": [
                        {
                            "id": "l2o1s1",
                            "name": "screen5"
                        },
                    ]
                },
                {
                    "id": "o2",
                    "screens": [
                        {
                            "id": "l2o2s1",
                            "name": "screen7"
                        }
                    ]
                }
            ]
        }
    ]
}

屏幕的输入不必只在一个文档中。它也可能存在于其他类别中。那么它应该只返回带有提到的屏幕 ID 的文档。

有没有办法像这样检索数据?

【问题讨论】:

  • 您的架构不支持这种查询。查询匹配的文档并在应用程序级别处理它们。如果您绝对必须在数据库端进行聚合,请使用聚合。这不会是有效的。

标签: mongodb nested-documents


【解决方案1】:

正如@alex-blex 建议的那样,您的架构不支持那种查询,但是如果您仍然想获得结果,您可以尝试使用聚合管道,但可能效率不高。

您可以尝试以下聚合管道:

db.collection.aggregate([
  {
    "$match": {
      "levels.orders.screens.id": {
        $in: [
          "l1o1s1",
          "l1o2s2",
          "l2o1s1",
          "l2o2s1"
        ]
      }
    }
  },
  {
    "$unwind": "$levels"
  },
  {
    "$unwind": "$levels.orders"
  },
  {
    "$unwind": "$levels.orders.screens"
  },
  {
    "$match": {
      "levels.orders.screens.id": {
        $in: [
          "l1o1s1",
          "l1o2s2",
          "l2o1s1",
          "l2o2s1"
        ]
      }
    }
  },
  {
    "$replaceRoot": {
      "newRoot": {
        _id: "$_id",
        "category": "$category",
        "levelId": "$levels.id",
        "orderId": "$levels.orders.id",
        "screens": "$levels.orders.screens"
      }
    }
  },
  {
    $group: {
      _id: {
        _id: "$_id",
        "levelId": "$levelId",
        "orderId": "$orderId",
        
      },
      "category": {
        $first: "$category"
      },
      "orderId": {
        $first: "$orderId"
      },
      "levelId": {
        $first: "$levelId"
      },
      "screens": {
        $push: "$screens"
      }
    }
  },
  {
    $project: {
      _id: "$_id._id",
      levelId: "$levelId",
      category: "category",
      "orders": {
        id: "$orderId",
        screens: "$screens"
      }
    }
  },
  {
    $group: {
      _id: {
        _id: "$_id",
        "levelId": "$levelId",
        
      },
      "category": {
        $first: "$category"
      },
      "levelId": {
        $first: "$levelId"
      },
      "orders": {
        $push: "$orders"
      }
    }
  },
  {
    $project: {
      _id: "$_id._id",
      category: "category",
      "levels": {
        id: "$levelId",
        orders: "$orders"
      }
    }
  },
  {
    $group: {
      _id: "$_id",
      "category": {
        $first: "$category"
      },
      "levels": {
        $push: "$levels"
      }
    }
  },
  
])

这是一个非常庞大且复杂的聚合管道,因此无法保证性能和效率,但您可以检查这是否适合您。

解释:

  1. $match 过滤出您所需的文档集,仅用于聚合管道的后期阶段。

  2. $unwind 展开 levels 数组

  3. $unwind 展开 orders 数组

  4. $unwind 展开 screens 数组

  5. $match 获取所需的确切 screens

  6. $replaceRoot 重新构造 JSON 文档,以便我们可以将展开的数组组合回来

  7. $groupscreens 分组到屏幕数组

  8. $project 再次重组生成的文档,以恢复原始结构

  9. $grouporders 分组到订单数组

  10. $project 再次重组生成的文档,以恢复原始结构

  11. $grouplevels 分组到levels 数组并返回我们的最终结果

您可以在this Mongo Playground查看结果

或者,您可以运行 agreation 管道直到第 5 阶段,然后在后端代码中将结果组合回您想要的格式。

【讨论】:

    猜你喜欢
    • 2019-03-24
    • 2016-02-17
    • 1970-01-01
    • 2018-08-20
    • 2018-09-24
    • 1970-01-01
    • 2015-07-01
    • 2015-02-09
    • 1970-01-01
    相关资源
    最近更新 更多