是否有Mongo函数可以根据字段过滤所有nested/subdocuments?

Is there a Mongo function for filtering all nested/subdocuments based on a field?

我在 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)。这是可能的还是必须在服务器端完成?

//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
                }
        }
}
>

您将能够通过几个 $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

使用$redact.

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

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