Mongodb array $push and $pull



我想从数组中提取一些值,同时尝试更新它。

    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还允许您返回修改后的文档(查看实际移动了哪些数组元素是必需的)。

以下包括以下示例:

  1. 将一个数组中的所有元素移动到另一个数组的末尾
  2. "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
});

最新更新