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

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

问题描述

我有重复键的问题。
长时间不能找到答案。请帮助我解决这个问题,或者解释为什么我会收到重复的密钥错误。

 跟踪:{[MongoError:E11000重复错误收集:project.monitor index:_id_ dup key:{:24392490}] 
name:'MongoError',
message:'E11000重复键错误集合:project.monitor索引:_id_ dup键:{:24392490 }',
driver:true,
index:0,
code:11000,
errmsg:'E11000 duplicate key error collection:project.monitor index:_id_ dup key: :/ / / / / / 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)
在processImmediate [as _immediateCallback](timers.js:368:17)

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



monitor.js:62-70



监视器模式

  var monitorSchema = db.Schema({
_id:{type:数字,默认值:utils.minute},
maxTicks:{type:Number,default:0},
ticks:{type:Number,default:0},
memory:{type:数字,默认值:0},
cpu:{type:Number,default:0},
reboot:{type:Number,default:0},
streams:db.Schema.Types 。混合
},{
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不是完全原子操作。想想起来,执行以下分离步骤:


  1. 查询已识别的文档进行提升。

  2. <如果文档存在,则原子地更新现有文档。
  3. 否则(文档不存在),原子插入一个包含查询字段和更新的新文档。所以步骤2和3都是原子的,但另一个upsert可能会在第1步之后发生,所以您的代码需要检查重复的键错误,并且那么如果发生这种情况,则重新尝试。在这一点上,你知道那个 _id 存在的文档,所以它总是会成功的。



    例如: p>

      var minute = utils.minute(); 
    Monitor.update({_id:minute},{$ inc:update},{upsert:true},function(err){
    if(err){
    if(err.code === 11000){
    //另一个upsert发生在upsert期间,再试一次,如果在运行时没有删除文档,可以省略
    // upsert选项
    Monitor.update({_id:minute},{$ inc:update},{upsert:true},
    函数(err){
    if(err){
    console.trace (错误);
    }
    });
    }
    else {
    console.trace(err);
    }
    }
    });

    请参阅这里相关文档。



    你可能还是想知道为什么如果插入是原子的,这可能会发生,但是这意味着在插入的文档完全写入之前不会发生更新,而不是没有其他插入具有相同的 _id的文档

    此外,您不需要在 _id 因为所有MongoDB集合在 _id 上有唯一的索引。所以你可以删除这一行:

      monitorSchema.index({_ id:-1}); //不需要


    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)
    

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

    monitor.js:62-70

    monitor schema

    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
    });
    

    index

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

    and increase by property

    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));
    };
    

    解决方案

    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. Query for the identified document to upsert.
    2. If the document exists, atomically update the existing document.
    3. Else (the document doesn't exist), atomically insert a new document that incorporates the query fields and the update.

    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.

    For example:

    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);
            }
        }
    });
    

    See here for the related documentation.

    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.

    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
    

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

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