目前,我使用save来添加单个文档。假设我有一个文档数组,我希望将它们存储为单个对象。是否有一种方法可以通过单个函数调用添加它们所有,并在完成后获取单个回调?我可以逐个添加所有文档,但管理回调以确定何时完成所有操作将会很麻烦。
目前,我使用save来添加单个文档。假设我有一个文档数组,我希望将它们存储为单个对象。是否有一种方法可以通过单个函数调用添加它们所有,并在完成后获取单个回调?我可以逐个添加所有文档,但管理回调以确定何时完成所有操作将会很麻烦。
Mongoose 现在支持向 Model.create 方法传递多个文档结构。引用其 API 示例,它可以传递一个数组或一组带有回调函数的对象:
Candy.create({ type: 'jelly bean' }, { type: 'snickers' }, function (err, jellybean, snickers) {
if (err) // ...
});
或者
var array = [{ type: 'jelly bean' }, { type: 'snickers' }];
Candy.create(array, function (err, jellybean, snickers) {
if (err) // ...
});
编辑:正如许多人所指出的那样,这并不是执行真正的批量插入 - 它只是隐藏了自己多次调用 save
的复杂性。 为了提高性能,下面的答案和评论解释了如何使用实际的Mongo驱动程序来实现批量插入。
Mongoose 4.4增加了一个方法叫做insertMany
验证文档数组并在它们全部有效时将它们插入到MongoDB的快捷方式。此函数比.create()更快,因为它只向服务器发送一次操作,而不是每个文档都发送一次。
引用自#723的vkarpov15:
折衷方案是insertMany()不会触发pre-save钩子,但它应该具有更好的性能,因为它只向数据库进行单次往返,而不是每个文档都进行一次。
该方法的签名与create
完全相同:
Model.insertMany([ ... ], (err, docs) => {
...
})
或者,使用 promises:
Model.insertMany([ ... ]).then((docs) => {
...
}).catch((err) => {
...
})
Model.insertMany(docs [, options])
时,将布尔值“false”传递给“options”参数,这样它就不会快速失败。 - aderchoxMongoose目前还没有实现批量插入功能(请参见问题#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();
当然,这只是一个权宜之计,我建议使用某种类型的流程控制库(我使用q,非常棒)。
if (--total)
何时会为假? - Gobliins在Mongoose中可以使用.insert()进行批量插入,除非您需要访问middleware。
Model.collection.insert(docs, options, callback)
https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L71-91
Model.collection.insert
?请提供一个例子。 - Stephan Kristyn使用 async.parallel,您的代码将如下所示:
async.parallel([obj1.save, obj2.save, obj3.save], callback);
由于在Mongoose中和async中的约定是相同的,即(err, callback),因此您不需要将它们包装在自己的回调函数中,只需将保存调用添加到数组中,等待所有完成时您将获得回调。
如果您使用mapLimit,您可以控制要并行保存多少个文档。在此示例中,我们并行保存10个文档,直到所有项目都成功保存。
async.mapLimit(myArray, 10, function(document, next){
document.save(next);
}, done);
myArray
包含1000万个项目。 - Stephan KristynbatchInsert()
调用可以插入多个文档,应该从原生mongodb驱动程序中使用这个功能。Mongoose是基于此驱动程序构建的,并不支持批量插入。这可能是有道理的,因为它被认为是MongoDB的对象文档建模工具。require('mongoose/node_modules/mongodb')
来使用该驱动程序(这个方法可能不太确定,但如果出现问题,您可以重新安装mongodb npm包)。然后就可以进行适当的batchInsert
了。mongodb
JavaScript驱动程序来解决。 - Ehtesh Choudhury较新版本的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).');
}
insertMany
函数插入多个文档。这只向服务器发送一个操作,并在命中mongo服务器之前使用Mongoose
验证所有文档。默认情况下,Mongoose
按照数组中存在的顺序插入项目。如果您不想保持任何顺序,请设置ordered:false
。ordered:true
时,验证和错误处理会成组发生,也就是说如果有一个失败,所有操作都将失败。ordered:false
时,验证和错误处理将单独进行,并且操作将继续进行。错误将以错误数组的形式返回。以下是另一种方法,不需要使用额外的库(未包括错误检查)
function saveAll( callback ){
var count = 0;
docs.forEach(function(doc){
doc.save(function(err){
count++;
if( count == docs.length ){
callback();
}
});
});
}
您可以使用由mongoose返回的Promise save
,mongoose中的Promise
并不具有所有特性,但是您可以使用此模块添加功能。
创建一个模块,增强mongoose承诺的所有功能。
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;
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);
})