Mongoose (mongodb) пакетная вставка?
Поддерживает ли Mongoose v3. 6+ пакетную вставку? Я искал несколько минут, но все, что соответствует этому запросу, - пару лет, и ответ был однозначным - нет.
Редактировать:
Для дальнейшего использования ответом будет использование Model.create()
. create()
принимает массив в качестве первого аргумента, поэтому вы можете передать свои документы для вставки в виде массива.
Смотрите Model.create() документацию
Ответы
Ответ 1
Model.create() против Model.collection.insert(): более быстрый подход
Model.create()
- плохой способ вставки, если вы работаете с очень большими объемами. Это будет очень медленно. В этом случае вы должны использовать Model.collection.insert
, который работает намного лучше. В зависимости от размера Model.create()
, Model.create()
может Model.create()
сбой! Пробовал с миллионом документов, не повезло. Использование Model.collection.insert
заняло всего несколько секунд.
Model.collection.insert(docs, options, callback)
-
docs
- массив документов для вставки; -
options
является необязательным объектом конфигурации - см. документацию -
callback(err, docs)
будет вызван после сохранения всех документов или возникновения ошибки. В случае успеха документы - это массив сохраняемых документов.
Как Mongoose автор указывает здесь, этот метод будет обходить любые процедуры проверки и получить доступ к драйверу Монго непосредственно. Это компромисс, который вы должны сделать, поскольку обрабатываете большой объем данных, иначе вы вообще не сможете вставить его в свою базу данных (помните, что мы говорим здесь о сотнях тысяч документов).
Простой пример
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()
. Параметры точно такие же, так что вы можете просто использовать его в качестве замены для вставки, и все должно работать просто отлично (ну, возвращаемое значение немного отличается, но вы, вероятно, не используете его в любом случае).
Ссылка
Ответ 2
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... */ });
Вы можете отслеживать его:
Ответ 3
В самом деле, вы можете использовать метод "create" Mongoose, он может содержать массив документов, см. этот пример:
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 за указание этого)
Ответ 4
Вы можете выполнить массовую вставку с использованием оболочки mongoDB, используя вставку значений в массив.
db.collection.insert([{values},{values},{values},{values}]);
Ответ 5
Вы можете выполнять массовую вставку с использованием мангуста, как самый высокий балл.
Но пример не может работать, он должен быть:
/* 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);
}
}
Не используйте экземпляр схемы для массовой вставки, вы должны использовать простой объект карты.
Ответ 6
Кажется, что при использовании мангуста существует предел более 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);
});
}
Ответ 7
Вот оба способа сохранения данных с помощью 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});
})
})
})
Ответ 8
Я использовал ссылку 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");
}
});
});
}
Ответ 9
Делимся рабочим и соответствующим кодом из нашего проекта:
//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);
});