Pertanyaan Bagaimana saya bisa menyimpan banyak dokumen secara bersamaan di Mongoose / Node.js?


Saat ini saya menggunakan simpan untuk menambahkan satu dokumen. Misalkan saya memiliki susunan dokumen yang ingin saya simpan sebagai objek tunggal. Apakah ada cara untuk menambahkan mereka semua dengan satu panggilan fungsi dan kemudian mendapatkan satu panggilan balik ketika selesai? Saya bisa menambahkan semua dokumen secara individual tetapi mengelola callback untuk bekerja ketika semuanya dilakukan akan bermasalah.


57
2018-04-22 08:45


asal


Jawaban:


Mongoose tidak memiliki sisipan massal diimplementasikan (lihat masalah # 723).

Karena Anda tahu jumlah dokumen yang Anda simpan, Anda dapat menulis sesuatu seperti ini:

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();

Ini, tentu saja, adalah solusi stop-gap dan saya akan merekomendasikan menggunakan beberapa jenis perpustakaan flow-control (saya gunakan q dan itu luar biasa).


31
2018-04-22 09:38



Mongoose sekarang mendukung melewati beberapa struktur dokumen Model.create. Untuk mengutip contoh API mereka, mendukung diteruskan baik array atau daftar objek varargs dengan callback di akhir:

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

Atau

var array = [{ type: 'jelly bean' }, { type: 'snickers' }];
Candy.create(array, function (err, jellybean, snickers) {
    if (err) // ...
});

Edit: Seperti yang banyak dicatat, ini tidak melakukan insert massal yang benar - itu hanya menyembunyikan kompleksitas panggilan save beberapa kali sendiri. Ada jawaban dan komentar di bawah ini menjelaskan cara menggunakan driver Mongo yang sebenarnya untuk mencapai insert massal untuk kepentingan kinerja.


83
2018-01-03 06:08



Mongoose 4.4 menambahkan metode yang disebut insertMany

Pintasan untuk memvalidasi susunan dokumen dan memasukkannya ke dalamnya   MongoDB jika semuanya valid. Fungsi ini lebih cepat daripada .create ()   karena hanya mengirim satu operasi ke server, bukan satu untuk masing-masing   dokumen.

Mengutip vkarpov15 dari masalah # 723:

Pengorbanan adalah bahwa insertMany () tidak memicu hook pre-save, tetapi harus memiliki kinerja yang lebih baik karena hanya membuat 1 round-trip ke database daripada 1 untuk setiap dokumen.

Tanda tangan metode ini identik dengan create:

Model.insertMany([ ... ], (err, docs) => {
  ...
})

Atau, dengan janji:

Model.insertMany([ ... ]).then((docs) => {
  ...
}).catch((err) => {
  ...
})

29
2018-03-18 17:05



Insert massal di Mongoose dapat dilakukan dengan .insert () kecuali Anda perlu mengakses middleware.

Model.collection.insert(docs, options, callback)

https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L71-91


24
2018-05-31 21:45



Menggunakan async parallel dan kode Anda akan terlihat seperti ini:

  async.parallel([obj1.save, obj2.save, obj3.save], callback);

Karena konvensi ini sama di Mongoose seperti pada async (err, callback) Anda tidak perlu membungkusnya dalam callback Anda sendiri, cukup tambahkan save call Anda dalam sebuah array dan Anda akan mendapatkan callback ketika semua sudah selesai.

Jika Anda menggunakan mapLimit Anda dapat mengontrol berapa banyak dokumen yang ingin Anda simpan secara paralel. Dalam contoh ini, kami menyimpan 10 dokumen secara paralel hingga semua item berhasil disimpan.

async.mapLimit(myArray, 10, function(document, next){
  document.save(next);
}, done);

11
2018-04-17 19:02



Saya tahu ini adalah pertanyaan lama, tetapi saya khawatir bahwa tidak ada jawaban yang benar di sini. Sebagian besar jawaban hanya berbicara tentang iterasi melalui semua dokumen dan menyimpannya masing-masing secara individual, yang merupakan ide BURUK jika Anda memiliki lebih dari beberapa dokumen, dan prosesnya diulangi bahkan untuk satu di banyak permintaan.

MongoDB secara khusus memiliki batchInsert()panggilan untuk memasukkan beberapa dokumen, dan ini harus digunakan dari driver mongodb asli. Mongoose dibangun pada driver ini, dan tidak memiliki dukungan untuk sisipan batch. Mungkin masuk akal karena seharusnya menjadi alat pemodelan dokumen Object untuk MongoDB.

Solusi: Mongoose dilengkapi dengan driver MongoDB asli. Anda dapat menggunakan driver itu dengan mewajibkannya require('mongoose/node_modules/mongodb') (tidak terlalu yakin tentang ini, tetapi Anda selalu dapat menginstal npm mongodb lagi jika tidak berhasil, tapi saya pikir itu harus) dan kemudian melakukan yang benar batchInsert


7
2018-05-09 10:11



Berikut ini cara lain tanpa menggunakan pustaka tambahan (tidak ada pemeriksaan kesalahan termasuk)

function saveAll( callback ){
  var count = 0;
  docs.forEach(function(doc){
      doc.save(function(err){
          count++;
          if( count == docs.length ){
             callback();
          }
      });
  });
}

6
2018-04-22 09:44



Versi lebih baru dari MongoDB mendukung operasi massal:

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

6
2017-08-14 16:49



Anda dapat menggunakan janji yang dikembalikan oleh luwak save, Promise di luwak tidak memiliki semua, tetapi Anda dapat menambahkan fitur dengan modul ini.

Buat modul yang meningkatkan janji luwak dengan semua.

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;

Kemudian gunakan dengan luwak:

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

2
2018-06-16 19:31



Tambahkan file bernama 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;

Kemudian dalam perubahan kode Anda, Anda perlu

var MongoClient = require("./mongoHelper.js");

Kemudian kapan waktunya untuk menyimpan panggilan (setelah Anda terhubung dan mengambil koleksi)

MongoClient.saveAny(data, collection, function(){db.close();});

Anda dapat mengubah penanganan kesalahan sesuai dengan kebutuhan Anda, kembalikan kesalahan dalam callback, dll.


0
2018-03-01 22:43