【问题标题】:How to save 1 million records to mongodb asyncronously?如何将100万条记录异步保存到mongodb?
【发布时间】:2015-03-21 04:14:50
【问题描述】:

我想使用 javascript 将 100 万条记录保存到 mongodb,如下所示:

for (var i = 0; i<10000000; i++) {
  model = buildModel(i);
  db.save(model, function(err, done) {
    console.log('cool');
  });
}

我试过了,它保存了大约 160 条记录,然后挂了 2 分钟,然后退出了。为什么?

【问题讨论】:

  • “炸毁”是什么意思?
  • 你需要扩大爆炸。 nodejs 是否崩溃,是否出错,是否只是无错误退出等等。我的第一个想法是 node 达到了它的内存限制
  • 它挂了一段时间,然后刷新了一些输出,然后退出了。它只保存了约 160 条记录。我抽象出我真正的问题,我想知道这是否可行? @VsevolodGoloviznin

标签: javascript node.js mongodb mongoose mongodb-query


【解决方案1】:

它崩溃了,因为您没有等待异步调用完成,然后再进行下一次迭代。这意味着您正在构建一个未解决的操作的“堆栈”,直到这导致问题。这个网站又叫什么名字?得到图片?

所以这不是进行"Bulk" 插入的最佳方式。幸运的是,除了前面提到的回调问题之外,底层的 MongoDB 驱动程序已经考虑到了这一点。事实上,有一个"Bulk API" 可以让这一切变得更好。并假设您已经将本机驱动程序作为db 对象提取。但我更喜欢只使用模型中的.collection 访问器和"async" 模块来让一切变得清晰:

var bulk = Model.collection.initializeOrderedBulkOp();
var counter = 0;

async.whilst(
  // Iterator condition
  function() { return count < 1000000 },

  // Do this in the iterator
  function(callback) {
    counter++;
    var model = buildModel(counter);
    bulk.insert(model);

    if ( counter % 1000 == 0 ) {
      bulk.execute(function(err,result) {
        bulk = Model.collection.initializeOrderedBulkOp();
        callback(err);
      });
    } else {
      callback();
    }
  },

  // When all is done
  function(err) {
    if ( counter % 1000 != 0 ) 
        bulk.execute(function(err,result) {
           console.log( "inserted some more" );
        });        
    console.log( "I'm finished now" ;
  }
);

不同之处在于在完成时使用“异步”回调方法而不是仅仅构建堆栈,而且还使用“批量操作 API”通过提交 1000 个批量更新语句中的所有内容来减轻异步写入调用条目。

这不仅不会像您自己的示例代码那样“构建一个函数执行堆栈”,而且通过不在单独的语句中发送所有内容,而是分解为可管理的“批次”来执行高效的“有线”事务用于服务器承诺。

【讨论】:

    【解决方案2】:

    你可能应该使用类似Async's eachLimit:

    // Create a array of numbers 0-999999
    var models = new Array(1000000);
    for (var i = models.length; i >= 0; i--)
      models[i] = i;
    
    // Iterate over the array performing a MongoDB save operation for each item
    // while never performing more than 20 parallel saves at the same time
    async.eachLimit(models, 20, function iterator(model, next){
      // Build a model and save it to the DB, call next when finished
      db.save(buildModel(model), next);
    }, function done(err, results){
      if (err) { // When an error has occurred while trying to save any model to the DB
        console.error(err);
      } else { // When all 1,000,000 models have been saved to the DB
        console.log('Successfully saved ' + results.length + ' models to MongoDB.');
      }
    });
    

    【讨论】:

    • 爱末日头像。但实际上 MongoDB API 有一个很好的方式来提交批量操作。不过,对并发操作的任何“限制”总是一个好主意。所以这是有效的。
    • @NeilLunn 谢谢。是的,我也不确定那个(尽管是同步的)buildModel() 函数有多昂贵,这就是为什么我将这些调用放在异步迭代器中,而不是在初始 for 循环中一次完成所有这些调用。附言我很高兴看到对优秀的 Doom Guy 的喜爱!
    猜你喜欢
    • 2021-12-30
    • 1970-01-01
    • 2016-01-11
    • 1970-01-01
    • 2023-03-11
    • 2012-06-14
    • 2016-09-17
    • 1970-01-01
    • 2021-11-27
    相关资源
    最近更新 更多