mongodb 聚合展开数组和无数组
mongodb aggregate unwind array and no array
我正在尝试使用 $unwind 编写聚合查询,无论该元素是否为数组。我知道 $unwind
不适用于任何数组元素,但我想知道是否有办法让它起作用,比如将此元素转换为数组。
我有一个 collection 这样的:
{
{"x" : 1, "y" : {"c" : 2, "i" : 3}},
{"x" : 1, "y" : [{"c" : 4, "i" : 5}, {"c" : 6, "i" : 7}]}
}
在我 $unwind
之前,我想我需要这样的东西:
{
{"x" : 1, "y" : [{"c" : 2, "i" : 3}]},
{"x" : 1, "y" : [{"c" : 4, "i" : 5}, {"c" : 6, "i" : 7}]}
}
到目前为止在$project
阶段我可以检查元素是否是数组,但我不知道如何使用这些信息来制作数组。我知道我可以使用 $push
来制作一个数组,但是如何保留未触及的数组元素而只是 $push
没有数组元素?
我试过这个:
{$group : {"_id" : "$x", "myArray" : {$push : {$cond : {if : "$isArray", then : "$y", else : ["$y"]}}}}}
使用上面的代码,我试图让所有元素都处于同一级别,但没有成功,因为 ["$y"]
returns 正是 (["$y"])
,没有评估,只是一个数组里面有字符串。
我不想 $unwind 一个空数组,我想将一个非数组元素转换成一个数组元素,这样我就可以 $unwind。
任何帮助将不胜感激。
的帮助下,这基本上可以满足您的需求
db.collection.aggregate([
{ "$project": {
"x": 1,
"y": {
"$cond": [
{ "$ifNull": [ "$y.0", null] },
"$y",
{ "$map": {
"input": ["A"],
"as": "el",
"in": "$y"
}}
]
}
}}
])
因此,这些首要条件通过基本测试数组元素 "first index" 的存在来得出 "is the element an array"。如果条件为真,则使用现有元素,即数组。
如果不是这样,元素通过 $map
函数和单个 "dummy" 数组元素 "transformed" 进入数组。
输出就是你想要的:
{
"_id" : ObjectId("557f9d9d655c7c61fdcb7909"),
"x" : 1,
"y" : [
{
"c" : 2,
"i" : 3
}
]
}
{
"_id" : ObjectId("557f9d9d655c7c61fdcb790a"),
"x" : 1,
"y" : [
{
"c" : 4,
"i" : 5
},
{
"c" : 6,
"i" : 7
}
]
}
我仍然会建议您在可能的情况下更改文档以在您的集合中实际包含一个数组元素,而不是将其放入管道中。像这样:
db.collection.find({ "y.0": { "$exists": false } }).forEach(function(doc) {
db.collection.update(
{ "_id": doc._id },
{ "$set": { "y": [doc.y] } }
)
})
我正在尝试使用 $unwind 编写聚合查询,无论该元素是否为数组。我知道 $unwind
不适用于任何数组元素,但我想知道是否有办法让它起作用,比如将此元素转换为数组。
我有一个 collection 这样的:
{
{"x" : 1, "y" : {"c" : 2, "i" : 3}},
{"x" : 1, "y" : [{"c" : 4, "i" : 5}, {"c" : 6, "i" : 7}]}
}
在我 $unwind
之前,我想我需要这样的东西:
{
{"x" : 1, "y" : [{"c" : 2, "i" : 3}]},
{"x" : 1, "y" : [{"c" : 4, "i" : 5}, {"c" : 6, "i" : 7}]}
}
到目前为止在$project
阶段我可以检查元素是否是数组,但我不知道如何使用这些信息来制作数组。我知道我可以使用 $push
来制作一个数组,但是如何保留未触及的数组元素而只是 $push
没有数组元素?
我试过这个:
{$group : {"_id" : "$x", "myArray" : {$push : {$cond : {if : "$isArray", then : "$y", else : ["$y"]}}}}}
使用上面的代码,我试图让所有元素都处于同一级别,但没有成功,因为 ["$y"]
returns 正是 (["$y"])
,没有评估,只是一个数组里面有字符串。
我不想 $unwind 一个空数组,我想将一个非数组元素转换成一个数组元素,这样我就可以 $unwind。
任何帮助将不胜感激。
db.collection.aggregate([
{ "$project": {
"x": 1,
"y": {
"$cond": [
{ "$ifNull": [ "$y.0", null] },
"$y",
{ "$map": {
"input": ["A"],
"as": "el",
"in": "$y"
}}
]
}
}}
])
因此,这些首要条件通过基本测试数组元素 "first index" 的存在来得出 "is the element an array"。如果条件为真,则使用现有元素,即数组。
如果不是这样,元素通过 $map
函数和单个 "dummy" 数组元素 "transformed" 进入数组。
输出就是你想要的:
{
"_id" : ObjectId("557f9d9d655c7c61fdcb7909"),
"x" : 1,
"y" : [
{
"c" : 2,
"i" : 3
}
]
}
{
"_id" : ObjectId("557f9d9d655c7c61fdcb790a"),
"x" : 1,
"y" : [
{
"c" : 4,
"i" : 5
},
{
"c" : 6,
"i" : 7
}
]
}
我仍然会建议您在可能的情况下更改文档以在您的集合中实际包含一个数组元素,而不是将其放入管道中。像这样:
db.collection.find({ "y.0": { "$exists": false } }).forEach(function(doc) {
db.collection.update(
{ "_id": doc._id },
{ "$set": { "y": [doc.y] } }
)
})