猫鼬(mongodb)批量插入?


114

的确猫鼬V3.6 +现在支持批量插入?我搜索了几分钟,但与此查询匹配的任何内容都已经存在了两年之久,答案是明确的。

编辑:

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

请参阅Model.create()文档


请参阅上一个问题的答案
JohnnyHK

谢谢。那是我发布后最终发现的。
Geuis

@Geuis,请添加您的编辑作为答案,并接受它来解决您的问题。
FilipDupanović2014年


Model.create()的速度很慢,如果您考虑插入大量文档,最好改用这种方法
Lucio Paiva 2015年

Answers:


162

Model.create()与Model.collection.insert():更快的方法

Model.create()如果要处理非常大的体积,这是做插入的一种坏方法。这将非常慢。在这种情况下,您应该使用Model.collection.insert,效果会更好。根据散装的大小,Model.create()甚至会崩溃!尝试过一百万份文件,没有运气。使用Model.collection.insert它只花了几秒钟。

Model.collection.insert(docs, options, callback)
  • docs 是要插入的文档数组;
  • options是可选的配置对象-请参阅文档
  • callback(err, 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);
    }
}

更新2019-06-22:虽然insert()仍然可以很好地使用它,但已不推荐使用insertMany()。参数完全相同,因此您可以将其用作即插即用替换,并且一切都应该可以正常工作(嗯,返回值有些不同,但是无论如何您都不会使用它)。

参考



请以猫鼬为例。
史蒂夫·K

15
由于Model.collection直接通过Mongo驱动程序进行操作,因此您将丢失所有包含验证和挂钩的整齐的猫鼬类东西。只是要记住一点。Model.create丢了钩子,但仍然要经过验证。如果需要全部,则必须进行迭代,并且new MyModel()
Pier-Luc Gendreau 2014年

1
@ Pier-LucGendreau绝对正确,但是一旦开始处理大量数据,就必须做出权衡。
Lucio Paiva 2015年

1
对新读者要小心:“在2.6版中进行了更改:insert()返回一个包含操作状态的对象”。没有更多的文档。
Mark Ni

117

猫鼬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... */ });

您可以在以下位置跟踪它:


2
目前,此方法不支持选项。
阿姆里

谢谢你的回答。知道应该对rawDocument进行什么解析吗?我已经尝试过使用Json对象数组,它插入的只是它们的ID。:(
Ondrej Tokar

4
这有bulkWrite什么不同?在这里看到:stackoverflow.com/questions/38742475/...
的Ondrej托卡里

insertMany对我不起作用。我有一个fatal error allocation failed。但是,如果我使用collection.insert,它将运行完美。
约翰

可以与猫鼬模式提供的额外内容一起使用吗?如果没有日期,则ex会添加数据dateCreated : { type: Date, default: Date.now },
插孔空白,

22

确实,您可以使用猫鼬的“创建”方法,它可以包含一个文档数组,请参见以下示例:

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指出这一点)


groups.google.com/forum/#!topic/mongoose-orm/IkPmvcd0kds-根据您的需要,链接有一个更好的选择。
arcseldon 2014年

你不是要{type:'jellybean'}代替{type:'jelly bean'}吗?顺便说一句。这些是什么奇怪的类型?它们是Mongoose API的一部分吗?
史蒂夫·K

2
那么,那是一个不好的命名选择,因为type通常在Mongoose中保留该名称以表示数据库对象的ADT。
史蒂夫·K

2
@sirbenbenji我更改了它,但这是官方文档中也有的示例。我认为没有必要为此投票。
benske 2014年

1
通过处理.collection属性,您可以绕过猫鼬(验证,“前置”方法...)
Derek

4

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

db.collection.insert([{values},{values},{values},{values}]);

猫鼬有没有办法批量插入?
SUNDARRAJAN K 2014年

1
YourModel.collection.insert()
比尔·达米

通过处理.collection属性,您可以绕过猫鼬(验证,“前置”方法...)
Derek

这不是猫鼬,原始collection.insert答案在这个答案之前的几个星期就给出了,并进行了更详细的解释。
Dan Dascalescu

4

您可以使用猫鼬作为最高分答案来执行批量插入。但是该示例无法正常工作,应该是:

/* 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);
    }
}

请勿将模式实例用于批量插入,而应使用普通地图对象。


第一个答案没有错,只有验证
卡·斯蒂布

1
通过处理.collection属性,您可以绕过猫鼬(验证,“前置”方法...)
Derek

4

这是使用insertMany保存数据和保存数据的两种方法

1)猫鼬保存的文档阵列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)猫鼬保存文档数组 .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});
        })
    })
})

3

似乎在使用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);
    });
}

1
通过处理.collection属性,您可以绕过猫鼬(验证,“前置”方法...)
Derek

0

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

//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);
    });

.insertMany解决方案已经给(和解释)在这个2016的答案
Dan Dascalescu
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.