我的理解是,在单个文档上使用upsert:true进行更新是一个原子操作,因此当集合没有唯一的索引字段时,这不会导致重复键错误,尤其是在主_id键上:

Order.update({ _id: order._id }, query, { upsert: true }, cb) // with mongoose

但这出现在mongod上.日志(log):

    2015-03-27T09:39:10.349-0400 I WRITE    [conn258236] update xyz.orders 
query: { _id: "6353f880-c6a7-4260-809f-98e0af27b9a2" } update: { $set: { ... 
} keyUpdates:0 writeConflicts:0 **exception: E11000 duplicate key error dup 
key: { : "6353f880-c6a7-4260-809f-98e0af27b9a2" } code:11000** numYields:1 
locks:{} 138ms


    2015-03-27T09:39:10.349-0400 I COMMAND  [conn258236] command xyz.$cmd 
command: update { update: "orders", writeConcern: { w: 1 }, ordered: true, 
updates: [ { q: { _id: "6353f880-c6a7-4260-809f-98e0af27b9a2" }, u: { $set: { 
... } }, multi: false, upsert: true } ] } keyUpdates:0 writeConflicts:0 
numYields:0 reslen:235 locks:{} 139ms

以下是db.orders.getIndexes()的输出:

{
    "v" : 1,
    "key" : {
        "_id" : 1
    },
    "name" : "_id_",
    "ns" : "xyz.orders"
},

我们正在使用MongoDB 3.0.0版和WiredTiger.

推荐答案

恐怕这是一个持续存在的问题.我也有同样的问题,我找到了一张关于这个的jira票:

https://jira.mongodb.org/browse/SERVER-14322

upsert可能会有两个更新:true,这两个更新都不会导致查找文档和插入新文档,这两个文档都与查询谓词的唯一索引冲突.

这里的"解决方案"是向客户端添加重试代码.

Mongodb相关问答推荐

为什么AllowDiskUse不能在$GROUP阶段的聚合管道中工作?

GO:如何在MongoDB中区分空字符串和nil

字段$set聚合导致错误美元($)前缀字段$concatArrays对于存储无效"

如何将空值单独分组?

减法聚合Mongo文档Golang

Mongo聚合的具体格式

Mongodb Timeseries / Golang - ['timestamp' 必须存在并包含有效的 BSON UTC 日期时间值]

Mongodb,在一个查询中用正则表达式更新部分字符串

有没有办法在 Prisma for MongoDB 的模式中显式声明 int32?

MongoDB:如何将所有文档合并到聚合管道中的单个文档中

Mongo 删除最后的文件

使用 mongodb 时是否需要规范化数据库?

.insertOne 不是函数

将MongoDB连接到前端?

Mongo 重启错误 -- /var/run/mongodb/mongod.pid 存在

mongodb-nodejs-driver,DeprecationWarning:collection.count 已弃用

MongoDB GridFS VS 直接磁盘 IO

MongoDb 数据库与集合

指定在 mongodb .js 脚本中使用哪个数据库

mongodb安装失败运行mongod