1

我是 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 的文档。

有什么办法可以像这样检索数据吗?

4

1 回答 1

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. $matchscreens以获取所需的确切信息

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

  7. $groupscreens对屏幕数组进行分组

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

  9. $grouporders对订单数组进行分组

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

  11. $group对级别数组进行分组levels并返回我们的最终结果

您可以在这个 Mongo Playground上查看结果

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

于 2020-09-19T11:45:19.863 回答