【问题标题】:Is there a Mongo function for filtering all nested/subdocuments based on a field?是否有用于基于字段过滤所有嵌套/子文档的 Mongo 函数?
【发布时间】:2021-01-16 03:36:33
【问题描述】:

我在 MongoDB 中有一些文档,其中的其他嵌套文档都带有“活动”字段。 例如:

{
    "id": "PRODUCT1",
    "name": "Product 1",
    "active": true,
    "categories": [
        {
            "id": "CAT-1",
            "active": true,
            "subcategories": [
                {
                    "id": "SUBCAT-1",
                    "active": false
                },
                {
                    "id": "SUBCAT-2",
                    "active": true
                }
            ]
        },
        {
            "id": "CAT-2",
            "active": false,
            "subcategories": [
                {
                    "id": "SUBCAT-3",
                    "active": true
                }
            ]
        }
    ]
}

有没有办法找到所有文档但只保留“活动”嵌套文档。

这是我想要的结果:

{
    "id": "PRODUCT1",
    "name": "Product 1",
    "active": true,
    "categories": [
        {
            "id": "CAT-1",
            "active": true,
            "subcategories": [
                {
                    "id": "SUBCAT-2",
                    "active": true
                }
            ]
        }
    ]
}

事先知道我不知道文档架构。这就是为什么我需要一种条件通配符投影...(即*.active=true)。这是可能的还是必须在服务器端完成?

【问题讨论】:

    标签: mongodb mongodb-query spring-data-mongodb


    【解决方案1】:
    //actual code out from mongo shell 4.2 on windows
    //sample document as shared in problem statement, query to find the document from //collection
    > db.products.find().pretty();
    {
            "_id" : ObjectId("5f748ee5377e73757bb7ceac"),
            "id" : "PRODUCT1",
            "name" : "Product 1",
            "active" : true,
            "categories" : [
                    {
                            "id" : "CAT-1",
                            "active" : true,
                            "subcategories" : [
                                    {
                                            "id" : "SUBCAT-1",
                                            "active" : false
                                    },
                                    {
                                            "id" : "SUBCAT-2",
                                            "active" : true
                                    }
                            ]
                    },
                    {
                            "id" : "CAT-2",
                            "active" : false,
                            "subcategories" : [
                                    {
                                            "id" : "SUBCAT-3",
                                            "active" : true
                                    }
                            ]
                    }
            ]
    }
    //verify mongo shell version no. for reference
    > db.version();
    4.2.6
    //using aggregate and $unwind you can query the inner array elements as shown below
    > db.products.aggregate([
    ... {$unwind: "$categories"},
    ... {$unwind: "$categories.subcategories"},
    ... {$match:{"active":true,
    ...          "categories.active":true,
    ...          "categories.subcategories.active":true}}
    ... ]).pretty();
    {
            "_id" : ObjectId("5f748ee5377e73757bb7ceac"),
            "id" : "PRODUCT1",
            "name" : "Product 1",
            "active" : true,
            "categories" : {
                    "id" : "CAT-1",
                    "active" : true,
                    "subcategories" : {
                            "id" : "SUBCAT-2",
                            "active" : true
                    }
            }
    }
    >
    

    【讨论】:

    • 我的问题是事先不知道架构。并非所有文档都有类别/子类别,有些还有其他带有“活动”的子文档,因此我的问题是在没有明确指定所有字段的情况下实现您刚刚所做的事情......我不确定这是否可能,但我想如果不是,请确认...
    • @SimoL。请为您的上述查询添加示例 JSON 文档。我会试试的。
    【解决方案2】:

    您将能够通过几个$map$reduce$filter 阶段来实现这一目标。

    db.collection.aggregate([
      {
        "$addFields": {
          "categories": {
            "$filter": {
              "input": "$categories",
              "cond": {
                $eq: [
                  "$$this.active",
                  true
                ]
              }
            }
          }
        }
      },
      {
        "$addFields": {
          "categories": {
            "$map": {
              "input": "$categories",
              "in": {
                "$mergeObjects": [
                  "$$this",
                  {
                    "subcategories": {
                      "$filter": {
                        "input": "$$this.subcategories",
                        "cond": {
                          $eq: [
                            "$$this.active",
                            true
                          ]
                        }
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      }
    ])
    

    执行上述操作将根据您的输入为您提供以下结果

    [
      {
        "_id": ObjectId("5a934e000102030405000000"),
        "active": true,
        "categories": [
          {
            "active": true,
            "id": "CAT-1",
            "subcategories": [
              {
                "active": true,
                "id": "SUBCAT-2"
              }
            ]
          }
        ],
        "id": "PRODUCT1",
        "name": "Product 1"
      }
    ]
    

    https://mongoplayground.net/p/fkkby-eibx2

    【讨论】:

      【解决方案3】:

      使用$redact

      db.collection.aggregate(
         [
           { $redact: {
              $cond: {
                 if: { $eq:["$active", true] },
                 then: "$$DESCEND",
                 else: "$$PRUNE"
               }
             }
           }
         ]
      );
      

      https://mongoplayground.net/p/7UMphkH5OWn

      【讨论】:

      • 这个方法好简洁,完全忘了$redact
      猜你喜欢
      • 2020-02-15
      • 2021-06-29
      • 2018-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多