node.js - Mongoose(mongodb)批量插入?

Mongoose v3.6 +现在支持批量插入吗? 我已经搜索了几分钟,但是这个查询的任何内容都是几年前的答案,答案是明确的。

编辑:

为了将来参考,答案是使用Model.create(). create()接受数组作为其第一个参数,因此您可以将文档作为数组插入。

请参见Model.create()文档

Geuis asked 2019-07-29T07:37:41Z
9个解决方案
145 votes

Model.create()vs Model.collection.insert():一种更快的方法

callback(err, docs)是一种不好的方法,如果你正在处理非常大的批量。 这将是非常缓慢的。 在这种情况下,你应该使用Model.collection.insert,它表现得更好。 根据批量的大小,Model.create()甚至会崩溃! 试过一百万份文件,没有运气。 使用Model.collection.insert只花了几秒钟。

Model.collection.insert(docs, options, callback)
  • callback(err, docs)是要插入的文档数组;
  • callback(err, docs)是一个可选的配置对象 - 请参阅docs
  • 保存所有文档或发生错误后将调用callback(err, docs)。 成功时,docs是持久化文档的数组。

正如Mongoose的作者在这里指出的,这种方法将绕过任何验证程序并直接访问Mongo驱动程序。 这是你必须要做的权衡,因为你正在处理大量的数据,否则你根本无法将它插入你的数据库(请记住我们在这里谈论成千上万的文档)。

一个简单的例子

var Potato = mongoose.model('Potato', PotatoSchema);

var potatoBag = [/* a humongous amount of potato objects */];

Potato.collection.insert(potatoBag, onInsert);

function onInsert(err, docs) {
    if (err) {
        // TODO: handle error
    } else {
        console.info('%d potatoes were successfully stored.', docs.length);
    }
}

参考

  • Mongodb文档
  • Google小组讨论批量插入的Aaron Heckman
Lucio Paiva answered 2019-07-29T07:38:48Z
103 votes

Mongoose 4.4.0现在支持批量插入

Mongoose 4.4.0引入了--true--使用模型方法.insertMany()进行批量插入。它比在.create()上循环或为其提供数组更快。

用法:

var rawDocuments = [/* ... */];

Book.insertMany(rawDocuments)
    .then(function(mongooseDocuments) {
         /* ... */
    })
    .catch(function(err) {
        /* Error handling */
    });

要么

Book.insertMany(rawDocuments, function (err, mongooseDocuments) { /* Your callback function... */ });

你可以跟踪它:

  • [https://github.com/Automattic/mongoose/issues/723]
  • [https://github.com/Automattic/mongoose/blob/1887e72694829b62f4e3547283783cebbe66b46b/lib/model.js#L1774]
Derek answered 2019-07-29T07:39:47Z
23 votes

的确,你可以使用Mongoose的“create”方法,它可以包含一个文件数组,请看这个例子:

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

回调函数包含插入的文档。您并不总是知道必须插入多少项(固定参数长度如上),因此您可以循环它们:

var insertedDocs = [];
for (var i=1; i<arguments.length; ++i) {
    insertedDocs.push(arguments[i]);
}

更新:更好的解决方案

一个更好的解决方案是使用Candy.collection.insert()而不是Candy.create() - 在上面的例子中使用 - 因为它更快(create()在每个项目上调用Model.save()所以它更慢)。

有关更多信息,请参阅Mongo文档:[http://docs.mongodb.org/manual/reference/method/db.collection.insert/]

(感谢arcseldon指出这一点)

benske answered 2019-07-29T07:40:51Z
5 votes

您可以使用插入数组中的值来使用mongoDB shell执行批量插入。

db.collection.insert([{values},{values},{values},{values}]);
SUNDARRAJAN K answered 2019-07-29T07:41:18Z
4 votes

您可以使用mongoose执行批量插入,作为最高得分答案。但是这个例子不行,应该是:

/* a humongous amount of potatos */
var potatoBag = [{name:'potato1'}, {name:'potato2'}];

var Potato = mongoose.model('Potato', PotatoSchema);
Potato.collection.insert(potatoBag, onInsert);

function onInsert(err, docs) {
    if (err) {
        // TODO: handle error
    } else {
        console.info('%d potatoes were successfully stored.', docs.length);
    }
}

不要使用模式实例进行批量插入,您应该使用普通的地图对象。

user2582680 answered 2019-07-29T07:41:53Z
3 votes

似乎使用mongoose时,使用时有超过1000个文档的限制

Potato.collection.insert(potatoBag, onInsert);

您可以使用:

var bulk = Model.collection.initializeOrderedBulkOp();

async.each(users, function (user, callback) {
    bulk.insert(hash);
}, function (err) {
    var bulkStart = Date.now();
    bulk.execute(function(err, res){
        if (err) console.log (" gameResult.js > err " , err);
        console.log (" gameResult.js > BULK TIME  " , Date.now() - bulkStart );
        console.log (" gameResult.js > BULK INSERT " , res.nInserted)
      });
});

但是,使用10000个文档进行测试时,这几乎快了两倍:

function fastInsert(arrOfResults) {
var startTime = Date.now();
    var count = 0;
    var c = Math.round( arrOfResults.length / 990);

    var fakeArr = [];
    fakeArr.length = c;
    var docsSaved = 0

    async.each(fakeArr, function (item, callback) {

            var sliced = arrOfResults.slice(count, count+999);
            sliced.length)
            count = count +999;
            if(sliced.length != 0 ){
                    GameResultModel.collection.insert(sliced, function (err, docs) {
                            docsSaved += docs.ops.length
                            callback();
                    });
            }else {
                    callback()
            }
    }, function (err) {
            console.log (" gameResult.js > BULK INSERT AMOUNT: ", arrOfResults.length, "docsSaved  " , docsSaved, " DIFF TIME:",Date.now() - startTime);
    });
}
ddennis answered 2019-07-29T07:42:29Z
2 votes

我使用async-forEach(async-forEach npm包文档的链接)来实现相同的功能。

我的代码片段如下所示。我在req.body中获取文档。

var forEach = require('async-foreach').forEach;    
exports.save_Ctrl = function (req, res) {    
//  var l=req.body;
//  console.log("length:",l.length);

 forEach(req.body, function(item, index, object,err) {

    console.log(req.body[index]);
    var post = new saveObj(req.body[index]);   

        //save model to MongoDB
    post.save(function (err) {
        if (err) {
            console.log('error saving :' + err.message);
            return err;
        }   
        else {
            console.log("Post saved");
        }
    });       

  });    
 }
nilakantha singh deo answered 2019-07-29T07:43:02Z
2 votes

以下是使用insertMany和save保存数据的两种方法

1)Mongoose保存批量文件insertMany

/* write mongoose schema model and export this */
var Potato = mongoose.model('Potato', PotatoSchema);

/* write this api in routes directory  */
router.post('/addDocuments', function (req, res) {
    const data = [/* array of object which data need to save in db */];

    Potato.insertMany(data)  
    .then((result) => {
            console.log("result ", result);
            res.status(200).json({'success': 'new documents added!', 'data': result});
    })
    .catch(err => {
            console.error("error ", err);
            res.status(400).json({err});
    });
})

2)Mongoose用.save()保存文件数组

这些文件将保存并行。

/* write mongoose schema model and export this */
var Potato = mongoose.model('Potato', PotatoSchema);

/* write this api in routes directory  */
router.post('/addDocuments', function (req, res) {
    const saveData = []
    const data = [/* array of object which data need to save in db */];
    data.map((i) => {
        console.log(i)
        var potato = new Potato(data[i])
        potato.save()
        .then((result) => {
            console.log(result)
            saveData.push(result)
            if (saveData.length === data.length) {
                res.status(200).json({'success': 'new documents added!', 'data': saveData});
            }
        })
        .catch((err) => {
            console.error(err)
            res.status(500).json({err});
        })
    })
})
Arpit answered 2019-07-29T07:43:54Z
1 votes

从我们的项目中共享工作和相关代码:

//documentsArray is the list of sampleCollection objects
sampleCollection.insertMany(documentsArray)  
    .then((res) => {
        console.log("insert sampleCollection result ", res);
    })
    .catch(err => {
        console.log("bulk insert sampleCollection error ", err);
    });
student answered 2019-07-29T07:44:22Z
translate from https://stackoverflow.com:/questions/16726330/mongoose-mongodb-batch-insert