使用mongo同时拉和添加

时间:2014-06-19 06:32:39

标签: mongodb mongodb-query

我有一个集合,可以将这些元素简化为:

{tags : [1, 5, 8]}

其中数组中至少有一个元素,所有元素都应该不同。我想用一个标签替换另一个标签,我认为不会有问题。所以我提出了以下问题:

db.colll.update({
  tags : 1
},{
  $pull: { tags: 1 },
  $addToSet: { tags: 2 }
}, {
  multi: true
})

很酷,所以它会找到所有带有我不需要的标签的元素(1),删除它并添加另一个(2)如果它不存在。问题是我收到错误:

  

"无法更新'标签'和'标签'在同一时间"

这基本上意味着我不能同时做pull和addtoset。有没有其他方法可以做到这一点?

当然我可以记住元素的所有ID,然后删除标记并添加单独的查询,但这听起来不太好。

4 个答案:

答案 0 :(得分:16)

错误几乎就是它的意思,因为你不能在同一个更新操作中对同一个“路径”的两个东西进行操作。您正在使用的两个运算符不会像您认为的那样按顺序处理。

您可以使用"bulk" operations API或其他形式的“批量”更新,以“顺序”方式执行此操作。在理由当然,也是相反的:

var bulk = db.coll.initializeOrderedBulkOp();
bulk.find({ "tags": 1 }).updateOne({ "$addToSet": { "tags":  2 } });
bulk.find({ "tags": 1 }).updateOne({ "$pull": { "tags": 1 } });

bulk.execute();

不保证没有其他任何东西可以尝试修改,但它与您目前的距离非常接近。

另请参阅包含多个文档的原始"update" command

答案 1 :(得分:5)

如果您要同时删除和添加,则可能会对地图进行建模,而不是设置'。如果是这样,对象的工作可能少于数组。

而不是数据作为数组:

{ _id: 'myobjectwithdata',
  data: [{ id: 'data1', important: 'stuff'},
         { id: 'data2', important: 'more'}]
}

将数据用作对象:

{ _id: 'myobjectwithdata',
  data: { data1: { important: 'stuff'},
          data2: { important: 'more'} }
}

单命令更新是:

db.coll.update(
  'myobjectwithdata', 
  { $set: { 'data.data1': { important: 'treasure' } }
);

努力完成这个答案herehere

答案 2 :(得分:2)

Mongo 4.4开始,$function聚合运算符允许应用自定义javascript函数来实现MongoDB查询语言不支持的行为。

并结合Mongo 4.2中对db.collection.update()的改进,可以接受聚合管道,从而允许根据字段自身的值更新字段

我们可以使用语言不容易允许的方式来操纵和更新数组:

// { "tags" : [ 1, 5, 8 ] }
db.collection.updateMany(
  { tags: 1 },
  [{ $set:
    { "tags":
      { $function: {
          body: function(tags) { tags.push(2); return tags.filter(x => x != 1); },
          args: ["$tags"],
          lang: "js"
      }}
    }
  }]
)
// { "tags" : [ 5, 8, 2 ] }

$function具有3个参数:

  • body,这是要应用的函数,其参数是要修改的数组。这里的功能仅包括push2放入数组并filter取出1
  • args,其中包含body函数作为参数的记录中的字段。在我们的情况下,"$tag"
  • lang,这是编写body函数的语言。当前仅js可用。

答案 3 :(得分:0)

如果您需要将数组中的一个值替换为另一个,请检查以下答案:

Replace array value using arrayFilters