我想从数组中提取一些值,同时尝试更新它。
userSchema.statics.experience = function (id,xper,delet,callback) {
var update = {
$pull:{
'profile.experience' : delet
},
$push: {
'profile.experience': xper
}
};
this.findByIdAndUpdate(id,update,{ 'new': true},function(err,doc) {
if (err) {
callback(err);
} else if(doc){
callback(null,doc);
}
});
};
我得到的错误是:
MongoError:异常:无法同时更新"profile.experience"one_answers"profile.reexperience"
我找到了这个解释:
问题是MongoDB不允许对相同更新调用中的相同属性。这意味着操作必须在两个单独的原子操作中进行。
你可以阅读这些帖子:
使用mongo 同时进行Pull和addtoset
单个语句中包含多个mongo更新运算符?
如果需要将一个数组值替换为另一个,可以使用arrayFilters进行更新。
(至少存在于mongo 4.2.1中)。
db.your_collection.update(
{ "_id": ObjectId("your_24_byte_length_id") },
{ "$set": { "profile.experience.$[elem]": "new_value" } },
{ "arrayFilters": [ { "elem": { "$eq": "old_value" } } ], "multi": true }
)
这将取代所有";旧值"阵列元素;new_value";。
从MongoDB 4.2开始
您可以尝试使用聚合管道更新阵列。
this.updateOne(
{ _id: id },
[
{
$set: {
"profile.experience": {
$concatArrays: [
{
$filter: {
input: "$profile.experience",
cond: { $ne: ["$$this", delet] },
},
},
[xper],
],
},
},
},
]
);
下面,一个mongoplayground正在做这项工作:
https://mongoplayground.net/p/m1C1LnHc0Ge
OBS:使用mongo定期更新查询是不可能的。
由于Mongo 4.2 findAndModify
支持聚合管道,这将允许在同一文档内的数组之间原子地移动元素。findAndModify
还允许您返回修改后的文档(查看实际移动了哪些数组元素是必需的)。
以下包括以下示例:
- 将一个数组中的所有元素移动到另一个数组的末尾
- "pop";一个数组的一个元素;"推";它到另一个数组
要运行这些示例,您需要以下数据:
db.test.insertMany( [
{
"_id": ObjectId("6d792d6a756963792d696441"),
"A": [ "8", "9" ],
"B": [ "7" ]
},
{
"_id": ObjectId("6d792d6a756963792d696442"),
"A": [ "1", "2", "3", "4" ],
"B": [ ]
}
]);
示例1-通过将数组A
移动到数组B
:来清空数组
db.test.findAndModify({
query: { _id: ObjectId("6d792d6a756963792d696441") },
update: [
{ $set: { "B": { $concatArrays: [ { $ifNull: [ "$B", [] ] }, "$A" ] } } },
{ $set: { "A": [] } }
],
new: true
});
结果:
{
"_id": {
"$oid": "6d792d6a756963792d696441"
},
"A": [],
"B": [
"7",
"8",
"9"
]
}
示例2.a-从数组A
弹出元素并将其推送到数组B
db.test.findAndModify({
query: { _id: ObjectId("6d792d6a756963792d696442"),
"A": {$exists: true, $type: "array", $ne: [] }},
update: [
{ $set: { "B": { $concatArrays: [ { $ifNull: [ "$B", [] ] }, [ { $first: "$A" } ] ] } } },
{ $set: { "A": { $slice: ["$A", 1, {$max: [{$subtract: [{ $size: "$A"}, 1]}, 1]}] } }}
],
new: true
});
结果:
{
"_id": {
"$oid": "6d792d6a756963792d696442"
},
"A": [
"2",
"3",
"4"
],
"B": [
"1"
]
}
示例2.b-从数组A
中弹出元素并将其推送到数组B
,但分两步使用临时占位符:
db.test.findAndModify({
query: { _id: ObjectId("6d792d6a756963792d696442"),
"temp": { $exists: false } },
update: [
{ $set: { "temp": { $first: "$A" } } },
{ $set: { "A": { $slice: ["$A", 1, {$max: [{$subtract: [{ $size: "$A"}, 1]}, 1]}] } }}
],
new: true
});
// do what you need to do with "temp"
db.test.findAndModify({
query: { _id: ObjectId("6d792d6a756963792d696442"),
"temp": { $exists: true } },
update: [
{ $set: { "B": { $concatArrays: [ { $ifNull: [ "$B", [] ] }, [ "$temp" ] ] } } },
{ $unset: "temp" }
],
new: true
});