> db.things.find()
{ "_id" : 1, "a" : [ ] }
{ "_id" : 2, "a" : [ { "x" : 2, "y" : 1 }, { "x" : 0, "y" : 1 } ] }
{ "_id" : 3, "a" : [ { "x" : 2, "y" : 5, "abitraryPropertyWhichShouldBeKept" : true } ] }
我想在magnitude
的每个子文档中添加一个计算属性,比如a
。我不想手动指定x
和y
,并且可能还有其他属性需要保留。到目前为止我的尝试(我必须手动指定x
和y
,我不应该这样做):
db.things.aggregate([
{
$addFields: {
a: {
$map: {
input: '$a',
as: 'item',
'in': {
x: '$$item.x',
y: '$$item.y',
magnitude: {
$sqrt: {
$add: [
{ $pow: ['$$item.x', 2], },
{ $pow: ['$$item.y', 2] }],
},
},
},
},
},
},
},
])
结果会丢掉我想要保留的额外密钥:
{ "_id" : 1, "a" : [ ] }
{ "_id" : 2, "a" : [ {
"x" : 2, "y" : 1, "magnitude" : 2.23606797749979 }, {
"x" : 0, "y" : 1, "magnitude" : 1 } ] }
{ "_id" : 3, "a" : [ { "x" : 2, "y" : 5, "magnitude" : 5.385164807134504 } ] }
我能想到的另一种方法是将$unwind
,$addFields
和$group
联系起来。但是为了防止$unwind
删除文档1,我必须在每个a
数组的末尾添加一个虚拟条目,然后在将它们再次组合在一起时将其丢弃。
是否有类似$map
的内容,但其行为类似于$addFields
,以便我可以在嵌套文档中添加属性?我是否真的必须指定子文档的所有可能键才能使用$map
?如果我不提前知道嵌套子文档中的键,那么我唯一的选择是$unwind
是否具有使用它所需的所有额外功能和环境?
这是我的$unwind
... $group
尝试。但是,正如你所看到的,我需要大量的阶段,如果我可以得到$addFields
- 就像$map
中的行为一样,或者某些表达式运算符会将对象合并在一起,就像JavaScript一样Object.assign()
:
db.things.aggregate([
{ // Add dummy to preserve documents during imminent $unwind
$addFields: {
a: {
$concatArrays: [ '$a', [ null, ], ],
},
},
},
{ $unwind: '$a', },
{ // Do actual calculation on single array element
$addFields: {
'a.magnitude': {
$sqrt: {
$add: [
{ $pow: ['$a.x', 2] },
{ $pow: ['$a.y', 2] },
],
},
},
},
},
{
$group: {
_id: '$_id',
a: { $push: '$a', },
item: { $first: '$$ROOT', },
},
},
{ // Remove dummy element
$addFields: {
'item.a': {
$slice: [ '$a', { $add: [ { $size: '$a', }, -1] } ],
},
},
},
{ $replaceRoot: { newRoot: '$item', }, },
])
结果可以正确保留原始数据中任何未预料到的密钥:
{ "_id" : 3, "a" : [ {
"x" : 2, "y" : 5, "abitraryPropertyWhichShouldBeKept" : true,
"magnitude" : 5.385164807134504 } ] }
{ "_id" : 2, "a" : [ {
"x" : 2, "y" : 1, "magnitude" : 2.23606797749979 }, {
"x" : 0, "y" : 1, "magnitude" : 1 } ] }
{ "_id" : 1, "a" : [ ] }
答案 0 :(得分:3)
您可以在3.5.6开发版本中使用mergeObjects
聚合运算符,该版本将在即将发布的3.6版本中使用。
db.things.aggregate([
{
"$addFields": {
"a": {
"$map": {
"input": "$a",
"as": "item",
"in": {
"$mergeObjects": [
"$$item",
{
"magnitude": {
"$sqrt": {
"$add": [
{
"$pow": [
"$$item.x",
2
]
},
{
"$pow": [
"$$item.y",
2
]
}
]
}
}
}
]
}
}
}
}
}
])
使用3.4.4&更高的产量释放。
在$map
中使用$arrayToObject
和$objectToArray
来保留现有键值,$concatArrays
合并计算出的键值数组。
db.things.aggregate([
{
"$addFields": {
"a": {
"$map": {
"input": "$a",
"as": "item",
"in": {
"$arrayToObject": {
"$concatArrays": [
{
"$objectToArray": "$$item"
},
[
{
"k": "magnitude",
"v": {
"$sqrt": {
"$add": [
{
"$pow": [
"$$item.x",
2
]
},
{
"$pow": [
"$$item.y",
2
]
}
]
}
}
}
]
]
}
}
}
}
}
}
])