猫鼬重复键错误与 upsert [英] Mongoose duplicate key error with upsert

查看:37
本文介绍了猫鼬重复键错误与 upsert的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有重复键的问题.好久没找到答案.请帮我解决这个问题或解释为什么我收到重复的密钥错误.

I have problem with duplicate key. Long time can`t find answer. Please help me solve this problem or explain why i get duplicate key error.

Trace: { [MongoError: E11000 duplicate key error collection: project.monitor index: _id_ dup key: { : 24392490 }]
name: 'MongoError',
message: 'E11000 duplicate key error collection: project.monitor index: _id_ dup key: { : 24392490 }',
driver: true,
index: 0,
code: 11000,
errmsg: 'E11000 duplicate key error collection: project.monitor index: _id_ dup key: { : 24392490 }' }
at /home/project/app/lib/monitor.js:67:12
at callback (/home/project/app/node_modules/mongoose/lib/query.js:2029:9)
at Immediate.<anonymous> (/home/project/app/node_modules/kareem/index.js:160:11)
at Immediate._onImmediate (/home/project/app/node_modules/mquery/lib/utils.js:137:16)
at processImmediate [as _immediateCallback] (timers.js:368:17)

但在监视器中我使用 upsert,那么为什么我会收到重复的错误??

but in monitor i use upsert, so why i get duplicate error??

monitor.js:62-70

监控架构

var monitorSchema = db.Schema({
   _id      : {type: Number, default: utils.minute},
   maxTicks : {type: Number, default: 0},
   ticks    : {type: Number, default: 0},
   memory   : {type: Number, default: 0},
   cpu      : {type: Number, default: 0},
   reboot   : {type: Number, default: 0},
streams  : db.Schema.Types.Mixed
}, {
collection: 'monitor',
strict: false
});

索引

monitorSchema.index({_id: -1});
Monitor = db.model('Monitor', monitorSchema);

并按属性增加

exports.increase = function (property, incr) {
    var update = {};
    update[property] = utils.parseRound(incr) || 1;
    Monitor.update({_id: utils.minute()}, {$inc: update}, {upsert: true}, function (err) {
        if (err) {
            console.trace(err);
        }
    });
};

utils.js

exports.minute = function () {
    return Math.round(Date.now() / 60000);
};

exports.parseRound = function (num, round) {
    if (isNaN(num)) return 0;
    return Number(parseFloat(Number(num)).toFixed(round));
};

推荐答案

导致文档插入的 upsert 不是完全原子操作.将 upsert 视为执行以下离散步骤:

An upsert that results in a document insert is not a fully atomic operation. Think of the upsert as performing the following discrete steps:

  1. 查询要更新插入的已识别文档.
  2. 如果文档存在,则自动更新现有文档.
  3. 否则(文档不存在),以原子方式插入一个包含查询字段和更新的新文档.

所以第 2 步和第 3 步都是原子的,但是在第 1 步之后可能会发生另一个 upsert,因此您的代码需要检查重复键错误,然后在发生这种情况时重试 upsert.此时,您知道具有该 _id 的文档存在,因此它总是会成功.

So steps 2 and 3 are each atomic, but another upsert could occur after step 1 so your code needs to check for the duplicate key error and then retry the upsert if that occurs. At that point you know the document with that _id exists so it will always succeed.

例如:

var minute = utils.minute();
Monitor.update({ _id: minute }, { $inc: update }, { upsert: true }, function(err) {
    if (err) {
        if (err.code === 11000) {
            // Another upsert occurred during the upsert, try again. You could omit the
            // upsert option here if you don't ever delete docs while this is running.
            Monitor.update({ _id: minute }, { $inc: update }, { upsert: true },
                function(err) {
                    if (err) {
                        console.trace(err);
                    }
                });
        }
        else {
            console.trace(err);
        }
    }
});

请参阅此处 相关文档.

您可能仍然想知道如果插入是原子的,为什么会发生这种情况,但这意味着插入的文档在完全写入之前不会发生更新,而不是没有其他具有相同 _id 可以出现.

You may still be wondering why this can happen if the insert is atomic, but what that means is that no updates will occur on the inserted document until it is completely written, not that no other insert of a doc with the same _id can occur.

此外,您无需在 _id 上手动创建索引,因为无论如何,所有 MongoDB 集合都在 _id 上具有唯一索引.所以你可以删除这一行:

Also, you don't need to manually create an index on _id as all MongoDB collections have a unique index on _id regardless. So you can remove this line:

monitorSchema.index({_id: -1}); // Not needed

这篇关于猫鼬重复键错误与 upsert的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆