MongoDb中的自动增量字段,具有异步批量插入

时间:2014-09-05 10:00:37

标签: javascript node.js mongodb mongoskin

我正在查看有关MongoDb中自动递增字段的文章。 http://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/

这在理论上似乎很好,但在我的应用程序中并不起作用,因为所有数据库调用都是异步的。 Ps,Im使用Mongoskin。 考虑一下:

var getNextSequence function (name) {
  db.counters.findAndModify({_id: 'invoiceNr'}, {}, {$inc: {seq: 1}}, {new: true}, function(err, doc) {
    if (err) {
      return next(err);
    }
    return doc.seq;
  });
}; 

var seq = getNextSequence('invoiceNr');
console.log(seq);

这个(Console.log)在执行时当然没有任何价值......

这让我想到了嵌套回调(经典的Node风格):

db.counters.findAndModify({_id: 'invoiceNr'}, {}, {$inc: {seq: 1}}, {new: true}, function(err, doc) {
  if (err) {
    return next(err);
  }
  var seq = getNextSequence('invoiceNr');
  // Do something with the seq, like using it when inserting another document.
});

这对于一个文档可以正常工作,但是如果我进行批量插入(传递要插入的多个文档的数组),我无法看到它是如何工作的。我需要批量插入。

回到循环和单个插入似乎不是一个好的解决方案。

你有什么好的解决方案吗?

1 个答案:

答案 0 :(得分:1)

因此,文档建议.findAndModify()用于此类操作,因为"更新/递增"的操作并检索结果是" atomic"操作。当然,如果你一次要插入500个文件,你不想回去"得到下一个增量" 500次,因为那将是疯狂的。但是你缺少这个概念。

谁说你必须增加1?简单地说,当您知道要插入500个项目时,您只需要将当前计数器增加501,以便下一个要求下一个计数器值的操作获得已经增加501的值,因此该部分是好的。

现在您要求计数器增加500块,您基本上只使用它们。所以你知道第一个使用的值基本上是从你的返回值减去500开始,并且你希望在实际返回的值上结束插入。

所以你想要一些像这样的代码:

var async = require('async'),
    mongo = require('mongoskin'),
    db = mongo.db('mongodb://localhost/test');


// The general incrementer

function getNextSequence( name, increment, callback ) {

  // Handling passing in "increment" as optional
  var args = Array.prototype.slice.call(arguments, 1);

  callback = args.pop();
  increment = args.length ? args.shift() || 1 : 1; // default 1

  db.collection('counters').findAndModify(
    { "_id": name },
    {},
    { "$inc": { "seq": increment } },
    { "new": true, "upsert": true },
    function(err,doc) {
      callback(err,doc.seq);
    }
  );

}

// Meat of your insertion logic

db.collection('target',function(err, collection) {

  var arrayToInsert = []; // simulating, but 500 items long assumed
  for (var x=0; x < 500; x++) {
    arrayToInsert.push({
      "x": x
    });
  }

  var bulk = collection.initializeOrderedBulkOp();

  async.waterfall(
    [
      function(callback) {
        getNextSequence('invoiceNo',arrayToInsert.length + 1,callback);
      },
      function(seq,callback) {
        var current = seq - arrayToInsert.length;
        var index = 0;

        async.whilst(
          function() { return index < arrayToInsert.length },
          function(callback) {
            doc = arrayToInsert[index];
            doc["invoice"] = current;
            bulk.insert( doc );
            index++;
            current++
            callback();
          },
          function(err) {
            bulk.execute(callback);
          }
        );
      }
    ],
    function(err,result) {
      if (err) throw err;
      // Log BulkWrite result
      console.log( JSON.stringify( result, undefined, 2 ) );
    }
  );

});

嗯,这是基本的模拟器,但你应该明白这个想法。基本上只是抓住一大堆价值&#34;您打算插入多少条目并使用每个&#34;值&#34;在插入实际文档时。

最糟糕的情况?插入在某处失败,并非所有值都在文档中结束。所以呢?没关系,因为关键是你已经增加了计数器,没有其他过程可以抓住那些相同的值#34;从柜台。

正如您可以从评论中收集到的,这是我试图引导您的地方,您可能已经完成了基础知识。没有什么可以说你不能将那个计数器增加1以上,所以只需增加你想要的数量。