【问题标题】:Mongodb: How to query nested documents and top level documentsMongodb:如何查询嵌套文档和顶级文档
【发布时间】:2021-10-27 00:53:22
【问题描述】:

我有以下文件。请注意,顶级文档具有与subDocument 相同的IDattribute1

{
    "ID": "1",
    "attribute1": "123",
    "subDocument": [
      {
        "ID": "2",
        "attribute1": "456",
      },
      {
        "ID": "3",
        "attribute1": "567",
      }
    ]
  },
  {
    "ID": "4",
    "attribute1": "123",
    "subDocument": [
      {
        "ID": "5",
        "attribute1": "456",
      }
    ]
  }

现在我需要一个可以基于IDattribute1 进行搜索的查询。如果我给ID =1,attribute1="123",它应该返回第一个顶级文档,如下所示:

{
    "ID": "1",
    "attribute1": "123"
  }

如果我给ID =2,attribute1="456",它应该返回子文档的项目,如下所示:

     {
        "ID": "2",
        "attribute1": "456",
      }

我该怎么做? playground

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    查询

    • 将根的标识/属性添加为子文档
    • 展开并替换ROOT =>每个成员都成为ROOT文档
    • $match 将文档与变量匹配

    Test code here

    aggregate(
    [{"$project": 
       {"subDocument": 
         {"$concatArrays": 
           ["$subDocument", [{"ID": "$ID", "attribute1": "$attribute1"}]]}}},
     {"$unwind": {"path": "$subDocument"}},
     {"$replaceRoot": {"newRoot": "$subDocument"}},
     {"$match" : {"ID" : your_id_var , "attribute1" : your_attr_var}}])
    

    编辑

    如果您有太多字段无法手动输入,您可以使用它,它将除"_id""subDocument" 之外的所有字段作为子文档

    Test code here

    aggregate(
    [{"$project": 
       {"subDocument": 
         {"$concatArrays": 
           ["$subDocument",
             [{"$arrayToObject": 
                {"$filter": 
                  {"input": {"$objectToArray": "$$ROOT"},
                   "cond": 
                   {"$and": 
                     [{"$ne": ["$$this.k", "subDocument"]},
                      {"$ne": ["$$this.k", "_id"]}]}}}}]]}}},
      {"$unwind": {"path": "$subDocument"}},
      {"$replaceRoot": {"newRoot": "$subDocument"}}
      {"$match" : {"ID" : your_id_var , "attribute1" : your_attr_var}}])
    

    我们没有像remove(object,k) 这样的运算符,所以这使得对象到数组、过滤器和返回对象(及其复杂)。

    还有另一种解决方案,但也很复杂。

    【讨论】:

    • 谢谢!如果我的顶级文档有很多属性。做 $concatArrays 时,我必须在这里列出它们吗? ["$subDocument", [{"ID": "$ID", "attribute1": "$attribute1","att2":"$att2".....}]
    • 我更新了,但我的意见是尽可能手写,并保留第一个查询
    【解决方案2】:

    您可以使用$unionWith 创建根文档和子文档的联合。然后将您的过滤器应用于联合结果。

    db.collection.aggregate([
      {
        $project: {
          "ID": 1,
          "attribute1": 1
        }
      },
      {
        "$unionWith": {
          "coll": "collection",
          "pipeline": [
            {
              "$unwind": "$subDocument"
            },
            {
              "$replaceRoot": {
                "newRoot": "$subDocument"
              }
            }
          ]
        }
      },
      {
        $match: {
          // your criteria here
          "ID": "2",
          "attribute1": "456",
          
        }
      }
    ])
    

    这里是Mongo playground 供您参考。

    【讨论】:

    • 谢谢,但 $unionWith 是在 4.4 版中引入的。在 4.2 版有什么办法吗?
    • @Takis_ 接受的答案应该在 4.2 版中有效。尝试理解他关于如何创建文档和子文档的联合的概念。
    【解决方案3】:

    我们知道为什么 Schema 是这样的,您将 ID 和 attribute1 放在文档级别以及子文档级别?尽管我们使用此模式,但您需要返回的文档只是您在查询中传递的相同过滤器值?文档 ID 和子文档 ID 会不会冲突?

    您还想通过以下方式获得此结果:

    如果您想根据匹配保留文档和子文档,请使用以下命令: https://mongoplayground.net/p/e0PaEvZhXIfhttps://mongoplayground.net/p/d8IKfSW4h87

    但是现在您只需要匹配的内容,然后在下面使用 https://mongoplayground.net/p/Ww1WqmY6wrV

    【讨论】:

      猜你喜欢
      • 2018-03-09
      • 1970-01-01
      • 2021-02-25
      • 2016-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-07
      相关资源
      最近更新 更多