MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Tentando fazer um upsert em massa com o Mongoose. Qual é a maneira mais limpa de fazer isso?


([email protected] , [email protected] )

TL;DR
await GasStation.collection.bulkWrite([ // <<==== use the model name
  {
    'updateOne': {
      'filter': { 'id': '<some id>' },
      'update': { '$set': { /* properties to update */ } },
      'upsert': true,  // <<==== upsert in every document
    }
  },
  /* other operations here... */
]);

Longa história:

Depois de lutar com a documentação ruim da API do Mongoose , resolvi o upsert em massa ajustando updateOne:{} operação no bulkWrite() método.

Algumas coisas não documentadas a serem consideradas:
// suppose:
var GasStation = mongoose.model('gasstation', gasStationsSchema);
var bulkOps = [ ];

// for ( ... each gasStation to upsert ...) {
  let gasStation = { country:'a', localId:'b', xyz:'c' };
  // [populate gasStation as needed]
  // Each document should look like this: (note the 'upsert': true)
  let upsertDoc = {
    'updateOne': {
      'filter': { 'country': gasStation.country, 'localId': gasStation.localId },
      'update': gasStation,
      'upsert': true
  }};
  bulkOps.push(upsertDoc);
// end for loop

// now bulkWrite (note the use of 'Model.collection')
GasStation.collection.bulkWrite(bulkOps)
  .then( bulkWriteOpResult => {
    console.log('BULK update OK');
    console.log(JSON.stringify(bulkWriteOpResult, null, 2));
  })
  .catch( err => {
    console.log('BULK update error');
    console.log(JSON.stringify(err, null, 2));
  });

As duas coisas principais aqui são problemas de documentação da API incompleta (no momento da redação, pelo menos):
  • 'upsert': true em cada documento . Isso não está documentado na API do Mongoose (), que geralmente se refere a node-mongodb-native condutor. Examinando updateOne neste driver , você pode pensar em adicionar 'options':{'upsert': true} , mas, não... isso não serve. Eu também tentei adicionar os dois casos ao bulkWrite(,[options],) argumento, também sem efeito.
  • GasStation.collection.bulkWrite() . Embora o método Mongoose bulkWrite() afirma que deve ser chamado Model.bulkWrite() (neste caso, GasStation.bulkWrite() ), que acionará MongoError: Unknown modifier: $__ . Então, Model.collection.bulkWrite() deve ser usado.

Além disso, observe:
  • Você não precisa usar o $set operador mongo no updateOne.update campo, uma vez que o mongoose o trata em caso de upsert (veja comentários de BulkWrite() no exemplo ).
  • Observe que meu índice exclusivo no esquema (necessário para que o upsert funcione corretamente) é definido como:

gasStationsSchema.index({ country: 1, localId: 1 }, { unique: true });

Espero que ajude.

==> EDITAR:(Mangusto 5?)

Conforme observado por @JustinSmith, o $set operador adicionado por Mongoose parece não estar mais funcionando. Talvez seja por causa do Mongoose 5?

De qualquer forma, usando $set explicitamente deve fazer:
'update': { '$set': gasStation },