如何在Mongoose/Node.js中同时保存多个文档?

Hoa*_*Hoa 66 mongoose mongodb node.js

目前我使用save来添加单个文档.假设我有一个文档数组,我希望将其存储为单个对象.有没有办法通过单个函数调用添加它们,然后在完成后获得单个回调?我可以单独添加所有文档,但是管理回调以便在完成所有操作时解决问题.

Pas*_*jac 88

Mongoose现在支持将多个文档结构传递给Model.create.引用他们的API示例,它支持传递一个数组或一个varargs对象列表,最后带有一个回调:

Candy.create({ type: 'jelly bean' }, { type: 'snickers' }, function (err, jellybean, snickers) {
    if (err) // ...
});
Run Code Online (Sandbox Code Playgroud)

要么

var array = [{ type: 'jelly bean' }, { type: 'snickers' }];
Candy.create(array, function (err, jellybean, snickers) {
    if (err) // ...
});
Run Code Online (Sandbox Code Playgroud)

编辑:正如许多人所说,这不会执行真正的批量插入 - 它只是隐藏了save自己多次调用的复杂性.下面有答案和评论解释如何使用实际的Mongo驱动程序来实现批量插入以保证性能.

  • 注意:这不是BULK插入 - 底层的mongoose实现循环遍历所有元素并逐个提交. (13认同)
  • 我想强调的是,如果您正在处理**大量文档**,这**不是**进行批量插入的最佳方法。请参阅http://stackoverflow.com/a/24848148/778272,其中包含更好的解释。 (2认同)

Pie*_*eau 46

Mongoose 4.4添加了一个名为的方法 insertMany

验证文档数组并将其插入MongoDB的快捷方式(如果它们全部有效).此函数比.create()更快,因为它只向服务器发送一个操作,而不是每个文档发送一个操作.

从问题#723引用vkarpov15 :

权衡是insertMany()不会触发预保存挂钩,但它应该具有更好的性能,因为它只对数据库进行1次往返,而不是每个文档1次.

该方法的签名与以下内容相同create:

Model.insertMany([ ... ], (err, docs) => {
  ...
})
Run Code Online (Sandbox Code Playgroud)

或者,承诺:

Model.insertMany([ ... ]).then((docs) => {
  ...
}).catch((err) => {
  ...
})
Run Code Online (Sandbox Code Playgroud)

  • 如果插入失败,则很多都没有插入,我已经进行了测试 (3认同)

小智 36

Mongoose还没有实现批量插入(参见问题#723).

既然您知道要保存的文档数量,就可以这样写:

var total = docArray.length
  , result = []
;

function saveAll(){
  var doc = docArray.pop();

  doc.save(function(err, saved){
    if (err) throw err;//handle error

    result.push(saved[0]);

    if (--total) saveAll();
    else // all saved here
  })
}

saveAll();
Run Code Online (Sandbox Code Playgroud)

当然,这是一个临时解决方案,我建议使用某种流量控制库(我使用q,它很棒).

  • 我不认为这是"并发".在完成上一个保存之前,不会调用每个保存. (5认同)
  • 你能用q提供解决方案吗? (2认同)
  • 我认为上面的答案已经很老了。mongoose 中有一个名为 insertMany() 的方法。检查https://mongoosejs.com/docs/api.html#model_Model.insertMany (2认同)

cyb*_*bat 25

Mongoose中的批量插入可以使用.insert()完成,除非您需要访问中间件.

Model.collection.insert(docs, options, callback)

https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L71-91


Chr*_*ren 12

使用async parallel,您的代码将如下所示:

  async.parallel([obj1.save, obj2.save, obj3.save], callback);
Run Code Online (Sandbox Code Playgroud)

由于Mongoose中的约定与async(错误,回调)中的约定相同,因此您无需将它们包装在自己的回调中,只需在数组中添加保存调用即可在完成所有操作后获得回调.

如果使用mapLimit,则可以控制要并行保存的文档数.在此示例中,我们将并行保存10个文档,直到所有项目都成功保存.

async.mapLimit(myArray, 10, function(document, next){
  document.save(next);
}, done);
Run Code Online (Sandbox Code Playgroud)

  • 有意思 - 你会介意用一个`myArray`给出一个真实可用的例子; 而myArray有1000万件物品. (2认同)

Mun*_*nim 8

我知道这是一个老问题,但它让我担心这里没有正确的答案.大多数答案只是讨论迭代所有文档并单独保存每个文档,如果您有多个文档,这是一个不好的想法,并且在许多请求中甚至会重复该过程.

MongoDB特别batchInsert()要求插入多个文档,这应该从本机mongodb驱动程序中使用.Mongoose是基于此驱动程序构建的,它不支持批量插入.它可能是有道理的,因为它应该是MongoDB的Object文档建模工具.

解决方案:Mongoose附带本机MongoDB驱动程序.您可以通过要求它来使用该驱动程序require('mongoose/node_modules/mongodb')(对此不太确定,但如果它不起作用,您可以再次安装mongodb npm,但我认为应该这样做)然后做一个正确的batchInsert

  • 错了,Pascal的回答完全忽略了这一点.需要批量插入的人往往需要它,因为他们想一次插入10,000,000件物品.如果没有批量插入,则需要几秒钟的操作可能需要数小时.Model.create是一个史诗般的失败,因为它假装是一个批量插入,但在引擎盖下它只是一个for循环. (2认同)

Pra*_*ena 8

使用insertMany函数插入多个文档。这只会向服务器发送一项操作,并Mongoose在到达 mongo 服务器之前验证所有文档。默认情况下,按照Mongoose项目在数组中存在的顺序插入项目。如果您同意不维持任何订单,请设置ordered:false

重要 - 错误处理:

ordered:true验证和错误处理发生在一组中时,意味着如果其中一个失败,那么一切都会失败。

ordered:false验证和错误处理单独发生时,操作将继续。错误将以错误数组的形式报告回来。


inx*_*pro 7

较新版本的MongoDB支持批量操作:

var col = db.collection('people');
var batch = col.initializeUnorderedBulkOp();

batch.insert({name: "John"});
batch.insert({name: "Jane"});
batch.insert({name: "Jason"});
batch.insert({name: "Joanne"});

batch.execute(function(err, result) {
    if (err) console.error(err);
    console.log('Inserted ' + result.nInserted + ' row(s).');
}
Run Code Online (Sandbox Code Playgroud)


min*_*dia 5

这是另一种不使用其他库的方法(不包括错误检查)

function saveAll( callback ){
  var count = 0;
  docs.forEach(function(doc){
      doc.save(function(err){
          count++;
          if( count == docs.length ){
             callback();
          }
      });
  });
}
Run Code Online (Sandbox Code Playgroud)