Mongodb 使用mongo同时拉动和添加设置

Mongodb 使用mongo同时拉动和添加设置,mongodb,mongodb-query,Mongodb,Mongodb Query,我有一个集合,其中的元素可以简化为: {tags:[1,5,8]} 数组中至少有一个元素,并且所有元素都应该不同。我想用一个标签替换另一个,我认为这不会有问题。因此,我提出了以下问题: db.colll.update({ tags : 1 },{ $pull: { tags: 1 }, $addToSet: { tags: 2 } }, { multi: true }) 很酷,所以它会找到所有有我不需要的标签的元素(1),删除它,如果它还没有,再添加一个(2)。问题是我得到了一

我有一个集合,其中的元素可以简化为:

{tags:[1,5,8]}

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

db.colll.update({
  tags : 1
},{
  $pull: { tags: 1 },
  $addToSet: { tags: 2 }
}, {
  multi: true
})
很酷,所以它会找到所有有我不需要的标签的元素(1),删除它,如果它还没有,再添加一个(2)。问题是我得到了一个错误:

“无法同时更新“标记”和“标记”

这基本上意味着我不能同时做pull和addtoset。我还有别的办法吗


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

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

您可以使用“顺序”或其他形式的“批量”更新来实现这一点。当然,这是合理的,反过来也是合理的:

var bulk=db.coll.initializeOrderedBulkOp();
bulk.find({“tags”:1}).updateOne({“$addToSet”:{“tags”:2});
bulk.find({“tags”:1}).updateOne({“$pull”:{“tags”:1}});
bulk.execute();
这并不能保证其他任何东西都不会尝试修改,但它与您当前得到的最接近


还可以查看包含多个文档的原始文档。

如果同时删除和添加文档,则可能是对“地图”建模,而不是对“集合”建模。如果是这样的话,一个对象的工作量可能比一个数组小

而不是将数据作为数组:

{ _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' } }
);

努力完成此答案。

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


Mongo4.4
开始,聚合操作符允许应用自定义javascript函数来实现MongoDB查询语言不支持的行为

再加上在
Mongo 4.2
中所做的改进,可以接受聚合管道,允许根据字段自身的值更新字段

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

// { "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
    ,它是要应用的函数,其参数是要修改的数组。这里的功能只是将
    推送
    ing
    2
    到数组中,然后
    过滤
    ing
    1
  • args
    ,其中包含
    函数体作为参数的记录字段。在我们的例子中,
    “$tag”
  • lang
    ,这是编写
    函数体的语言。目前只有
    js
    可用

谢谢你告诉我批量更新,但出于某种原因,我得到了:“errmsg”:“修饰符对字段进行操作,但我们找到了一个数字作为替代。例如:{$mod:{:…}}不是{$addToSet:183.0}”,但我发送的parseInt(ID)@salvadodali编辑得太快了。字段名丢失。@NeilLunn这是作为功能添加还是什么?我也有同样的问题——同时推拉。想做这件事似乎很正常,我希望能做这样的事。我是否应该向mongo jira发出功能请求?请注意,在批量操作中使用两个操作不是原子操作。第一个操作可能成功,但第二个操作没有成功;或者存在竞争条件。当然可以,但如果数据中的任何字段被索引,它就不起作用