是否有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"
}
]
使用$redact
.
db.collection.aggregate(
[
{ $redact: {
$cond: {
if: { $eq:["$active", true] },
then: "$$DESCEND",
else: "$$PRUNE"
}
}
}
]
);
我在 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"
}
]
使用$redact
.
db.collection.aggregate(
[
{ $redact: {
$cond: {
if: { $eq:["$active", true] },
then: "$$DESCEND",
else: "$$PRUNE"
}
}
}
]
);