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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10266512/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 15:34:48  来源:igfitidea点击:

How can I save multiple documents concurrently in Mongoose/Node.js?

node.jsmongodbmongoose

提问by Hoa

At the moment I use save to add a single document. Suppose I have an array of documents that I wish to store as single objects. Is there a way of adding them all with a single function call and then getting a single callback when it is done? I could add all the documents individually but managing the callbacks to work out when everything is done would be problematic.

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

采纳答案by diversario

Mongoose doesn't have bulk inserts implemented yet (see issue #723).

Mongoose 尚未实现批量插入(请参阅问题 #723)。

Since you know the number of documents you're saving, you could write something like this:

由于您知道要保存的文档数量,您可以编写如下内容:

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

This, of course, is a stop-gap solution and I would recommend using some kind of flow-control library (I use qand it's awesome).

当然,这是一个权宜之计,我建议使用某种流量控制库(我使用q并且它很棒)。

回答by Pascal Zajac

Mongoose does now support passing multiple document structures to Model.create. To quote their API example, it supports being passed either an array or a varargs list of objects with a callback at the end:

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

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

Or

或者

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

Edit:As many have noted, this does not perform a true bulk insert - it simply hides the complexity of calling savemultiple times yourself. There are answers and comments below explaining how to use the actual Mongo driver to achieve a bulk insert in the interest of performance.

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

回答by Pier-Luc Gendreau

Mongoose 4.4 added a method called insertMany

Mongoose 4.4 添加了一个方法叫做 insertMany

Shortcut for validating an array of documents and inserting them into MongoDB if they're all valid. This function is faster than .create() because it only sends one operation to the server, rather than one for each document.

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

Quoting vkarpov15 from issue #723:

引用问题#723 中的vkarpov15 :

The tradeoffs are that insertMany() doesn't trigger pre-save hooks, but it should have better performance because it only makes 1 round-trip to the database rather than 1 for each document.

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

The method's signature is identical to create:

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

Model.insertMany([ ... ], (err, docs) => {
  ...
})

Or, with promises:

或者,承诺:

Model.insertMany([ ... ]).then((docs) => {
  ...
}).catch((err) => {
  ...
})

回答by cyberwombat

Bulk inserts in Mongoose can be done with .insert() unless you need to access middleware.

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

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

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

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

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

回答by Christian Landgren

Use async paralleland your code will look like this:

使用异步并行,您的代码将如下所示:

  async.parallel([obj1.save, obj2.save, obj3.save], callback);

Since the convention is the same in Mongoose as in async (err, callback) you don't need to wrap them in your own callbacks, just add your save calls in an array and you will get a callback when all is finished.

由于 Mongoose 中的约定与 async (err, callback) 中的约定相同,因此您不需要将它们包装在您自己的回调中,只需将保存调用添加到数组中,当所有完成时您将收到一个回调。

If you use mapLimit you can control how many documents you want to save in parallel. In this example we save 10 documents in parallell until all items are successfully saved.

如果您使用 mapLimit,您可以控制要并行保存的文档数量。在本例中,我们并行保存 10 个文档,直到成功保存所有项目。

async.mapLimit(myArray, 10, function(document, next){
  document.save(next);
}, done);

回答by Munim

I know this is an old question, but it worries me that there are no properly correct answers here. Most answers just talk about iterating through all the documents and saving each of them individually, which is a BAD idea if you have more than a few documents, and the process gets repeated for even one in many requests.

我知道这是一个老问题,但我担心这里没有正确的答案。大多数答案只是谈论遍历所有文档并单独保存每个文档,如果您有多个文档,这是一个坏主意,并且该过程甚至会重复许多请求中的一个。

MongoDB specifically has a batchInsert()call for inserting multiple documents, and this should be used from the native mongodb driver. Mongoose is built on this driver, and it doesn't have support for batch inserts. It probably makes sense as it is supposed to be a Object document modelling tool for MongoDB.

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

Solution: Mongoose comes with the native MongoDB driver. You can use that driver by requiring it require('mongoose/node_modules/mongodb')(not too sure about this, but you can always install the mongodb npm again if it doesn't work, but I think it should) and then do a proper batchInsert

解决方案:Mongoose 自带 MongoDB 驱动。您可以通过要求使用该驱动程序require('mongoose/node_modules/mongodb')(对此不太确定,但是如果它不起作用,您始终可以再次安装 mongodb npm,但我认为它应该),然后执行适当的操作batchInsert

回答by inxilpro

Newer versions of MongoDB support bulk operations:

较新版本的 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).');
}

回答by mindandmedia

Here is another way without using additional libraries (no error checking included)

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

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

回答by Kristian Benoit

You can use the promise returned by mongoose save, Promisein mongoose does not have all, but you can add the feature with this module.

您可以使用 mongoose 返回的承诺savePromise在 mongoose 中没有全部,但您可以使用此模块添加该功能。

Create a module that enhance mongoose promise with all.

创建一个模块来增强猫鼬的承诺。

var Promise = require("mongoose").Promise;

Promise.all = function(promises) {
  var mainPromise = new Promise();
  if (promises.length == 0) {
    mainPromise.resolve(null, promises);
  }

  var pending = 0;
  promises.forEach(function(p, i) {
    pending++;
    p.then(function(val) {
      promises[i] = val;
      if (--pending === 0) {
        mainPromise.resolve(null, promises);
      }
    }, function(err) {
      mainPromise.reject(err);
    });
  });

  return mainPromise;
}

module.exports = Promise;

Then use it with mongoose:

然后与猫鼬一起使用:

var Promise = require('./promise')

...

var tasks = [];

for (var i=0; i < docs.length; i++) {
  tasks.push(docs[i].save());
}

Promise.all(tasks)
  .then(function(results) {
    console.log(results);
  }, function (err) {
    console.log(err);
  })

回答by Praveena

Use insertManyfunction to insert many documents. This sends only one operation to the server and Mongoosevalidates all the documents before hitting the mongo server. By default Mongooseinserts item in the order they exist in the array. If you are ok with not maintaining any order then set ordered:false.

使用insertMany函数插入多个文档。这仅向服务器发送一个操作并Mongoose在访问 mongo 服务器之前验证所有文档。默认情况下Mongoose,按照它们在数组中存在的顺序插入项目。如果您可以不维护任何顺序,则设置ordered:false.

Important - Error handling:

重要 - 错误处理:

When ordered:truevalidation and error handling happens in a group means if one fails everything will fail.

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

When ordered:falsevalidation and error handling happens individually and operation will be continued. Error will be reported back in an array of errors.

ordered:false验证和错误处理单独发生时,操作将继续。错误将在错误数组中报告。