使用自定义_id值时在mongodb中进行upserts

aar*_*les 15 mongodb

如果文档不存在,我需要插入一个文档.我知道"upsert"选项可以做到这一点,但我有一些特殊的需求.

首先,我需要仅使用_id字段创建文档,但前提是它不存在.我的_id字段是由我生成的数字(不是ObjectId).如果我使用"upsert"选项,那么我得到"Mod on _id not allowed"

db.mycollection.update({ _id: id }, { _id: id }, { upsert: true });
Run Code Online (Sandbox Code Playgroud)

我知道我们不能在$ set中使用_id.

所以,我的问题是:如果有任何方法在mongodb中以原子方式创建"如果不存在"?

编辑:由@Barrie提出这个工作(使用nodejs和mongoose):

var newUser = new User({ _id: id });
newUser.save(function (err) {               
    if (err && err.code === 11000) {            
            console.log('If duplicate key the user already exists', newTwitterUser);
        return;
    }
    console.log('New user or err', newTwitterUser);
});
Run Code Online (Sandbox Code Playgroud)

但我仍然想知道这是否是最佳方式.

Nat*_*arr 26

我遇到了同样的问题,但为我的需求找到了更好的解决方案.如果只是从更新对象中删除_id属性,则可以使用相同的查询样式.所以,如果一开始你得到一个错误:

db.mycollection.update({ _id: id }, {$set: { _id: id, name: 'name' }}, { upsert: true });
Run Code Online (Sandbox Code Playgroud)

改为使用这个:

db.mycollection.update({ _id: id }, {$set: { name: 'name' }}, { upsert: true });
Run Code Online (Sandbox Code Playgroud)

这样更好,因为它适用于插入和更新.

  • 如问题中所述,这是否适用于不是ObjectID的_id? (2认同)

Mik*_*ank 6

更新:使用_id的$setOnInsertupsert 可以在没有的情况下完成,正如@Barrie上面的解释.

诀窍是使用$setOnInsert:{_id:1}upsert,这样只有在插入时才会写入_id,而从不用于更新.

只是,有一个错误阻止它工作直到v2.6 - 我只是在2.4上尝试它并且它不起作用.

我使用的解决方法是使用另一个具有唯一索引的ID字段.例如.$setOnInsert:{myId:1}.


小智 5

您可以只使用insert()。如果您指定的带有_id的文档已经存在,则insert()将会失败,将不会进行任何修改-因此,当您对用户使用insert()时,默认情况下“正在创建,如果不存在”创建了_id。

  • 这仍然无法解决竞态条件,即在插入之后和后续更新之前删除文档。 (2认同)