Как я могу сохранить несколько документов одновременно в Мангуст / узел.Джей?
на данный момент я использую сохранить, чтобы добавить один документ. Предположим у меня есть массив документов, которые я хочу хранить как отдельные объекты. Есть ли способ добавить их все с помощью одного вызова функции, а затем получить один обратный вызов, когда это будет сделано? Я мог бы добавить все документы по отдельности, но управление обратными вызовами для разработки, когда все будет сделано, будет проблематичным.
13 ответов:
Мангуст еще не реализовал массовые вставки (см. выпуск #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 и это здорово).
Мангуст теперь поддерживает передачу нескольких структур документа модель.создать. Чтобы процитировать их пример API, он поддерживает передачу либо массива, либо списка объектов varargs с обратным вызовом в конце:
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) // ... });
Edit: как многие отметили, это не выполняет истинную массовую вставку - она просто скрывает сложность вызова
save
несколько раз сам. Есть ответы и комментарии ниже объясняя, как использовать фактический драйвер Mongo для достижения объемной вставки в интересах производительности.
Мангуст 4.4 добавлен метод под названием
insertMany
ярлык для проверки массива документов и вставки их в MongoDB, если они все действительны. Эта функция работает быстрее .создавать() потому что он отправляет только одну операцию на сервер, а не по одной для каждого документ.
цитирование vkarpov15 из выпуска #723:
компромиссы заключаются в том, что insertMany() не запускает предварительное сохранение крючки, но он должен иметь лучшую производительность, потому что он делает только 1 туда и обратно в базу данных, а не 1 для каждого документа.
сигнатура метода идентична
create
:Model.insertMany([ ... ], (err, docs) => { ... })
или, с обещаниями:
Model.insertMany([ ... ]).then((docs) => { ... }).catch((err) => { ... })
Навальные вставки в Мангусте можно сделать С.вставка() если вам нужно получить доступ к промежуточным.
Model.collection.insert(docs, options, callback)
https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L71-91
использовать асинхронный параллельный и ваш код будет выглядеть так:
async.parallel([obj1.save, obj2.save, obj3.save], callback);
Если вы используете mapLimit вы можете контролировать, сколько документов вы хотите сохранить параллельно. В этом примере мы сохраняем 10 документов параллельно, пока все элементы не будут успешно сохранено.
async.mapLimit(myArray, 10, function(document, next){ document.save(next); }, done);
Я знаю, что это старый вопрос, но меня беспокоит, что здесь нет правильных ответов. Большинство ответов просто говорят о повторении всех документов и сохранении каждого из них по отдельности, что является плохой идеей, если у вас есть более нескольких документов, и процесс повторяется даже для одного из многих запросов.
MongoDB специально имеет
batchInsert()
вызов для вставки нескольких документов, и это должно использоваться из родного драйвера mongodb. Мангуста построен на этом драйвере, и он не имеет поддержки для пакетных вставок. Вероятно, это имеет смысл, поскольку он должен быть инструментом моделирования объектного документа для MongoDB.решение: Мангуст поставляется с родным драйвером MongoDB. Вы можете использовать этот драйвер, требуя его
require('mongoose/node_modules/mongodb')
(не слишком уверен в этом, но вы всегда можете установить mongodb npm снова, если он не работает, но я думаю, что он должен) , а затем сделать правильныйbatchInsert
вот еще один способ без использования дополнительных библиотек (без проверки ошибок)
function saveAll( callback ){ var count = 0; docs.forEach(function(doc){ doc.save(function(err){ count++; if( count == docs.length ){ callback(); } }); }); }
новые версии 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).'); }
вы можете использовать обещание, возвращенный мангуста
save
,Promise
в мангусте есть не все, но вы можете добавить эту функцию с помощью этого модуля.создайте модуль, который улучшит обещание мангуста со всеми.
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); })
Добавить файл с именем mongoHelper.js
var MongoClient = require('mongodb').MongoClient; MongoClient.saveAny = function(data, collection, callback) { if(data instanceof Array) { saveRecords(data,collection, callback); } else { saveRecord(data,collection, callback); } } function saveRecord(data, collection, callback) { collection.save ( data, {w:1}, function(err, result) { if(err) throw new Error(err); callback(result); } ); } function saveRecords(data, collection, callback) { save ( data, collection, callback ); } function save(data, collection, callback) { collection.save ( data.pop(), {w:1}, function(err, result) { if(err) { throw new Error(err); } if(data.length > 0) save(data, collection, callback); else callback(result); } ); } module.exports = MongoClient;
тогда в вашем коде изменение вам требуется
var MongoClient = require("./mongoHelper.js");
затем, когда пришло время, чтобы сохранить вызов (после подключения и извлечения коллекции)
MongoClient.saveAny(data, collection, function(){db.close();});
вы можете изменить обработку ошибок в соответствии с вашими потребностями, передать обратно ошибка обратного вызова и т. д.
Это старый вопрос, но он появился первым для меня в результатах google при поиске "Мангуст вставить массив документов".
есть два варианта модели.создать() [мангуст] и модель.коллекция.вставьте () [mongodb], который вы можете использовать. Просмотрите более подробное обсуждение здесь плюсов / минусов каждого варианта:
вот пример использования MongoDB в
Model.collection.insert()
прямо в Мангуста. Обратите внимание, что если у вас не так много документов, скажем, менее 100 документов, вам не нужно использовать массовую операцию MongoDB (посмотреть этот).MongoDB также поддерживает массовую вставку через передачу массива документы в БД.коллекция.метод Insert ().
var mongoose = require('mongoose'); var userSchema = mongoose.Schema({ email : { type: String, index: { unique: true } }, name : String }); var User = mongoose.model('User', userSchema); function saveUsers(users) { User.collection.insert(users, function callback(error, insertedDocs) { // Here I use KrisKowal's Q (https://github.com/kriskowal/q) to return a promise, // so that the caller of this function can act upon its success or failure if (!error) return Q.resolve(insertedDocs); else return Q.reject({ error: error }); }); } var users = [{email: 'foo@bar.com', name: 'foo'}, {email: 'baz@bar.com', name: 'baz'}]; saveUsers(users).then(function() { // handle success case here }) .fail(function(error) { // handle error case here });
использовать
insertMany
функция для вставки многих документов. Это отправляет только одну операцию на сервер иMongoose
проверяет все документы перед попаданием на сервер mongo. По умолчаниюMongoose
вставляет элемент в порядке их существования в массиве. Если вы в порядке с не поддержанием любого порядка, то установитеordered:false
.важно - ошибка обработки:
, когда
ordered:true
проверка и обработка ошибок происходит в группе означает, если не все неудача., когда
ordered:false
проверка и обработка ошибок происходит индивидуально и операция будет продолжена. Ошибка будет сообщена обратно в массиве ошибок.