bin*_*nki 2 mongodb aggregation-framework
> 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 } ] }
Run Code Online (Sandbox Code Playgroud)
我想为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] }],
},
},
},
},
},
},
},
])
Run Code Online (Sandbox Code Playgroud)
结果删除了我想保留的额外密钥:
{ "_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 } ] }
Run Code Online (Sandbox Code Playgroud)
我能想到的唯一的另一种方法是链接$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', }, },
])
Run Code Online (Sandbox Code Playgroud)
结果正确保留原始数据中的任何意外键:
{ "_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" : [ ] }
Run Code Online (Sandbox Code Playgroud)
您可以使用mergeObjects3.5.6 开发版本中提供的聚合运算符,该版本将纳入即将发布的 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
]
}
]
}
}
}
]
}
}
}
}
}
])
Run Code Online (Sandbox Code Playgroud)
使用 3.4.4 及更高版本的生产版本。
在 a 中使用$arrayToObject和来保留现有的键值并合并计算出的键值数组。$objectToArray$map$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
]
}
]
}
}
}
]
]
}
}
}
}
}
}
])
Run Code Online (Sandbox Code Playgroud)