Пакетная вставка Mongoose (mongodb)?

114

Поддерживает ли Mongoose v3.6 + пакетную вставку? Я искал несколько минут, но всему, что соответствует этому запросу, уже несколько лет, и ответ был однозначным отрицательным.

Редактировать:

Для дальнейшего использования, ответ - использовать Model.create(). create()принимает массив в качестве своего первого аргумента, поэтому вы можете передать свои документы для вставки в виде массива.

См. Документацию Model.create ()

Geuis
источник
См. Этот ответ на предыдущий вопрос.
JohnnyHK
Спасибо. Это то, что я нашел после публикации.
Geuis
@Geuis, пожалуйста, добавьте свою правку в качестве ответа и примите ее, чтобы разрешить свой вопрос.
Филип Дупанович
Model.create () работает медленно, и если вы планируете вставить огромное количество документов, лучше использовать этот подход .
Лучио Пайва

Ответы:

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)будет вызываться после того, как все документы будут сохранены или возникнет ошибка. В случае успеха 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(). Параметры точно такие же, поэтому вы можете просто использовать его как замену, и все должно работать нормально (ну, возвращаемое значение немного другое, но вы, вероятно, все равно его не используете).

Ссылка

Лусио Пайва
источник
1
groups.google.com/forum/#!topic/mongoose-orm/IkPmvcd0kds Говорит все на самом деле.
arcseldon
Приведите пример с Mongoose.
Steve K
15
Поскольку Model.collectionпроходит напрямую через драйвер Mongo, вы теряете все удобные функции мангуста, включая проверку и хуки. Просто нужно иметь в виду. Model.createтеряет ловушки, но все равно проходит проверку. Если вы хотите все это, вы должны повторять иnew MyModel()
Пьер-Люк Gendreau
1
@ Pier-LucGendreau Вы абсолютно правы, но вам придется пойти на компромисс, когда вы начнете иметь дело с огромным объемом данных.
Лучио Пайва,
1
Будьте осторожны с новыми читателями: «Изменено в версии 2.6: insert () возвращает объект, содержащий статус операции». Больше никаких документов.
Марк Ни
117

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

Вы можете отследить это:

Дерек
источник
2
В настоящее время этот метод не поддерживает параметры.
Амри
Спасибо за ответ. Есть идеи, какой должен быть синтаксический анализ rawDocuments? Я пробовал это с массивом объектов Json, и все, что он вставил, было только их идентификаторами. :(
Ондрей Токар
4
Чем это отличается от bulkWrite? См. Здесь: stackoverflow.com/questions/38742475/…
Ондрей Токар,
insertMany у меня не работает. Я получил fatal error allocation failed. Но если я использую collection.insert, он отлично работает.
Джон
Будет ли это работать с дополнительным материалом, который предоставляет схема мангуста? ex добавит ли это данные, если дата не существуетdateCreated : { type: Date, default: Date.now },
jack blank
22

Действительно, вы можете использовать метод 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
источник
groups.google.com/forum/#!topic/mongoose-orm/IkPmvcd0kds - в зависимости от того, что вы хотите, ссылка может быть лучше.
arcseldon
Разве вы не имеете в виду {type:'jellybean'}вместо {type:'jelly bean'}? Btw. что это за странные типы? Являются ли они частью Mongoose API?
Steve K
2
Что ж, тогда это плохой выбор именования, поскольку typeобычно в Mongoose зарезервировано для обозначения ADT объекта базы данных.
Steve K
2
@sirbenbenji Я изменил его, но этот пример также присутствует в официальной документации. Думаю, для этого не было необходимости голосовать против.
Бенске
1
Обращаясь к свойству .collection, вы обходите Mongoose (проверка, предварительные методы ...)
Дерек,
4

Вы можете выполнить массовую вставку с помощью оболочки mongoDB, вставив значения в массив.

db.collection.insert([{values},{values},{values},{values}]);
SUNDARRAJAN K
источник
есть ли способ в мангусте для объемной вставки?
SUNDARRAJAN K
1
YourModel.collection.insert()
Bill Dami
Обращаясь к свойству .collection, вы обходите Mongoose (проверка, предварительные методы ...)
Дерек,
Это не мангуст, и необработанный collection.insertответ был дан за несколько недель до этого ответа и объяснен гораздо более подробно.
Дэн Даскалеску
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);
    }
}

Не используйте экземпляр схемы для массовой вставки, вы должны использовать простой объект карты.

пользователь2582680
источник
Первый ответ не является неправильным, он просто подтвержден
Лука Стиб
1
Обращаясь к свойству .collection, вы обходите Mongoose (проверка, предварительные методы ...)
Дерек,
4

Вот оба способа сохранения данных с помощью 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
источник
3

Кажется, что при использовании мангуста существует ограничение на более 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
источник
1
Обращаясь к свойству .collection, вы обходите Mongoose (проверка, предварительные методы ...)
Дерек,
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 году ответ .
Дэн Даскалеску