MongoDB 如果条件匹配则更新数组
MongoDB update array if condition matches
我正在寻找 MongoDB 聚合管道,它使用条件语句更新数组。
我的数据如下所示:
{
"_id": 1,
"locations": [
{
"controllerID": 1,
"timestamp": 1234
},
{
"controllerID": 2,
"timestamp": 2342
}
]
},...
可能的新条目:
{
"controllerID": 2,
"timestamp": //will be set automatically
}
起初我想匹配 _id(不是问题),然后如果具有 newest/latest 时间戳的元素具有不同的 controllerID,则将新条目推送到 locations 数组。
推送新位置对象时,将自动设置时间戳。
示例 1
输入:
{
"controllerID": 2,
}
预期结果:
{
"_id": 1,
"locations": [
{
"controllerID": 1,
"timestamp": 1234
},
{
"controllerID": 2,
"timestamp": 2342
}//noting is added because the newset entry in the array has the same controllerID
]
},
示例 2
输入:
{
"controllerID": 1,
}
预期结果:
{
"_id": 1,
"locations": [
{
"controllerID": 1,
"timestamp": 1234
},
{
"controllerID": 2,
"timestamp": 2342
},
{//added because the controllerID is different to te last element
"controllerID": 1,
"timestamp": 4356
}
]
},
提前致谢!
这是一个解决方案。
var candidate = 2;
rc=db.foo.update({}, // add matching criteria here; for now, match ALL
[
[
// We cannot say "if condition then set fld = X else do nothing".
// We must say "set fld to something based on condition."
// The common pattern becomes:
// "Set fld to (if condition then X else fld)"
// in other words, set the fld to *itself*
//
// Note the use of the dot operator on the $locations field.
// Also, not sure about what sort of new timestamp is desired so let's
// just throw in an ISODate() for now.
{$set: {'locations': {$cond: [
{$ne:[candidate, {$last:'$locations.controllerID'}]}, // IF not same as candidate...
{$concatArrays: ['$locations',
// $concatArrays wants arrays, not objects, so we must wrap our new
// object with [] to make an array of 1:
[ {controllerId:candidate,timestamp:new ISODate() } ]
]}, // THEN concat a new entry to end of existing locations
'$locations' // ELSE just set back to existing locations
]}
}}
],
{multi:true}
);
引擎“足够聪明”,意识到将字段设置为自身不会不会触发修改,因此该方法是高效的,不会重写整个匹配对象集;这可以在 update()
调用的输出中看到,例如:
printjson(rc);
{ "nMatched" : 1002, "nUpserted" : 0, "nModified" : 1 }
我正在寻找 MongoDB 聚合管道,它使用条件语句更新数组。 我的数据如下所示:
{
"_id": 1,
"locations": [
{
"controllerID": 1,
"timestamp": 1234
},
{
"controllerID": 2,
"timestamp": 2342
}
]
},...
可能的新条目:
{
"controllerID": 2,
"timestamp": //will be set automatically
}
起初我想匹配 _id(不是问题),然后如果具有 newest/latest 时间戳的元素具有不同的 controllerID,则将新条目推送到 locations 数组。 推送新位置对象时,将自动设置时间戳。
示例 1
输入:
{
"controllerID": 2,
}
预期结果:
{
"_id": 1,
"locations": [
{
"controllerID": 1,
"timestamp": 1234
},
{
"controllerID": 2,
"timestamp": 2342
}//noting is added because the newset entry in the array has the same controllerID
]
},
示例 2
输入:
{
"controllerID": 1,
}
预期结果:
{
"_id": 1,
"locations": [
{
"controllerID": 1,
"timestamp": 1234
},
{
"controllerID": 2,
"timestamp": 2342
},
{//added because the controllerID is different to te last element
"controllerID": 1,
"timestamp": 4356
}
]
},
提前致谢!
这是一个解决方案。
var candidate = 2;
rc=db.foo.update({}, // add matching criteria here; for now, match ALL
[
[
// We cannot say "if condition then set fld = X else do nothing".
// We must say "set fld to something based on condition."
// The common pattern becomes:
// "Set fld to (if condition then X else fld)"
// in other words, set the fld to *itself*
//
// Note the use of the dot operator on the $locations field.
// Also, not sure about what sort of new timestamp is desired so let's
// just throw in an ISODate() for now.
{$set: {'locations': {$cond: [
{$ne:[candidate, {$last:'$locations.controllerID'}]}, // IF not same as candidate...
{$concatArrays: ['$locations',
// $concatArrays wants arrays, not objects, so we must wrap our new
// object with [] to make an array of 1:
[ {controllerId:candidate,timestamp:new ISODate() } ]
]}, // THEN concat a new entry to end of existing locations
'$locations' // ELSE just set back to existing locations
]}
}}
],
{multi:true}
);
引擎“足够聪明”,意识到将字段设置为自身不会不会触发修改,因此该方法是高效的,不会重写整个匹配对象集;这可以在 update()
调用的输出中看到,例如:
printjson(rc);
{ "nMatched" : 1002, "nUpserted" : 0, "nModified" : 1 }