MongoDB 在空数组上展开聚合
MongoDB aggregation with unwind on empty array
我在 MongoDB 中有一个文档集合,其中每个文档都有一个包含数组的子文档。
{
_id: <id>
key1: "value1",
key2: "value2",
...
versions: [
{ version: 2, key1: <othervalue2>, key2: <othervalue2>}
{ version: 1, key1: <othervalue2>, key2: <othervalue2>}
]
}
我想查询集合和 return 文档及其所有字段,以及与特定参数匹配的数组元素(或当 none 匹配时为空数组)。使用我当前的代码,我只能在数组中至少有一个元素匹配时才能得到结果。
我正在使用这些参数进行聚合:
{$match: {_id: <someID>}},
{$unwind: '$versions'},
{$match: {'versions.version': {$gte: <version>}}},
{$group: {_id: '$_id', key1: {$first: '$key1'}, ..., 'versions': {$push: '$versions'}}
例如,查询 where arrayelement.version >= 2 应该 return (这适用于当前代码):
{
_id: <id>
key1: "value1",
key2: "value2",
...
versions: [
{ version: 2, key1: <othervalue2>, key2: <othervalue2>}
]
}
并查询 arrayelement.version >= 4 应该 return:
{
_id: <id>
key1: "value1",
key2: "value2",
...
versions: []
}
None 我见过的解决方案解决了即使数组为空时 returning 对象的问题。这甚至可能吗?
您可以检查版本数组是否为空,如果是,则添加一些占位符,例如一个空文档。省略管道的其余部分可能是这样的:
[
{
"$project" : {
"versions" : {
"$cond" : {
"if" : {"$eq" : [{"$size" : "$versions" }, 0]},
"then" : [{ }],
"else" : "$versions"
}
},
"_id" : 1
}
},
{
"$unwind" : "$versions"
}
]
请记住,您的管道中的 {$match: {'versions.version'}}
会将其过滤掉,因此您必须调整这部分。
感谢 zero323 让我走上正轨。完整过滤器如下
{$match: {_id: <someid>}},
{
"$project" : {
"versions" : {
"$cond" : {
"if" : {$or: [{$eq : [{$size : "$versions" }, 0]},{$eq : ["$version", <version>]}]},
"then" : [null],
"else" : "$versions"
}
},
"_id" : 1,
"key1": 1,
"key2": 1,
...
"version": 1
}
},
{$unwind: '$versions'},
{$match: {$or: [{'versions.version':{ $exists: false}},{'versions.version': {$gte: <version>}}]}},
{$group: {_id:'$_id',key1:{$first: '$key1'}, key2:{$first: '$key2'},...,version:{$first:'$version'},versions:{$push: '$versions'}}},
{
"$project" : {
"versions" : {
"$cond" : {
"if" : {$eq : ["$versions", [null]]},
"then" : [],
"else" : "$versions"
}
},
"_id" : 1,
"key1": 1,
"key2": 1,
...
"version": 1
}
}
从MongoDb 3.2开始,$unwind
运算符支持preserveNullAndEmptyArrays:<boolean>
.
所以当preserveNullAndEmptyArrays:true
时,它也会包含没有任何数据或空数据的值。
代码更改-
{$unwind: {path: '$versions', preserveNullAndEmptyArrays: true} },
欲了解更多信息,请访问 - https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/#document-operand-with-options
我在 MongoDB 中有一个文档集合,其中每个文档都有一个包含数组的子文档。
{
_id: <id>
key1: "value1",
key2: "value2",
...
versions: [
{ version: 2, key1: <othervalue2>, key2: <othervalue2>}
{ version: 1, key1: <othervalue2>, key2: <othervalue2>}
]
}
我想查询集合和 return 文档及其所有字段,以及与特定参数匹配的数组元素(或当 none 匹配时为空数组)。使用我当前的代码,我只能在数组中至少有一个元素匹配时才能得到结果。
我正在使用这些参数进行聚合:
{$match: {_id: <someID>}},
{$unwind: '$versions'},
{$match: {'versions.version': {$gte: <version>}}},
{$group: {_id: '$_id', key1: {$first: '$key1'}, ..., 'versions': {$push: '$versions'}}
例如,查询 where arrayelement.version >= 2 应该 return (这适用于当前代码):
{
_id: <id>
key1: "value1",
key2: "value2",
...
versions: [
{ version: 2, key1: <othervalue2>, key2: <othervalue2>}
]
}
并查询 arrayelement.version >= 4 应该 return:
{
_id: <id>
key1: "value1",
key2: "value2",
...
versions: []
}
None 我见过的解决方案解决了即使数组为空时 returning 对象的问题。这甚至可能吗?
您可以检查版本数组是否为空,如果是,则添加一些占位符,例如一个空文档。省略管道的其余部分可能是这样的:
[
{
"$project" : {
"versions" : {
"$cond" : {
"if" : {"$eq" : [{"$size" : "$versions" }, 0]},
"then" : [{ }],
"else" : "$versions"
}
},
"_id" : 1
}
},
{
"$unwind" : "$versions"
}
]
请记住,您的管道中的 {$match: {'versions.version'}}
会将其过滤掉,因此您必须调整这部分。
感谢 zero323 让我走上正轨。完整过滤器如下
{$match: {_id: <someid>}},
{
"$project" : {
"versions" : {
"$cond" : {
"if" : {$or: [{$eq : [{$size : "$versions" }, 0]},{$eq : ["$version", <version>]}]},
"then" : [null],
"else" : "$versions"
}
},
"_id" : 1,
"key1": 1,
"key2": 1,
...
"version": 1
}
},
{$unwind: '$versions'},
{$match: {$or: [{'versions.version':{ $exists: false}},{'versions.version': {$gte: <version>}}]}},
{$group: {_id:'$_id',key1:{$first: '$key1'}, key2:{$first: '$key2'},...,version:{$first:'$version'},versions:{$push: '$versions'}}},
{
"$project" : {
"versions" : {
"$cond" : {
"if" : {$eq : ["$versions", [null]]},
"then" : [],
"else" : "$versions"
}
},
"_id" : 1,
"key1": 1,
"key2": 1,
...
"version": 1
}
}
从MongoDb 3.2开始,$unwind
运算符支持preserveNullAndEmptyArrays:<boolean>
.
所以当preserveNullAndEmptyArrays:true
时,它也会包含没有任何数据或空数据的值。
代码更改-
{$unwind: {path: '$versions', preserveNullAndEmptyArrays: true} },
欲了解更多信息,请访问 - https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/#document-operand-with-options