微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

MongoDB:在第三级嵌入文档中找到匹配的元素

如何解决MongoDB:在第三级嵌入文档中找到匹配的元素

我是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"
                        }
                    ]
                },"screens": [
                        {
                            "id": "l2o2s1","name": "screen7"
                        },{
                            "id": "l2o2s2","name": "screen8"
                        }
                    ]
                }
            ]
        }
    ]
}

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

 {
    "category":"cat_1","name":"screen1"
                        }
                    ]
                },"screens": [
                        {
                            "id": "l1o2s2",]
                },"name": "screen7"
                        }
                    ]
                }
            ]
        }
    ]
}

屏幕的输入不必仅在单个文档中。它也可能存在于其他类别中。那么它应该只返回具有上述屏幕ID的文档。

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

解决方法

正如@ 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",{
    "$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"
      }
    }
  },"orders": {
        $push: "$orders"
      }
    }
  },"levels": {
        id: "$levelId",orders: "$orders"
      }
    }
  },{
    $group: {
      _id: "$_id","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

上查看结果

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。