([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 aobulkWrite(,[options],)
argumento, também sem efeito.GasStation.collection.bulkWrite()
. Embora o método Mongoose bulkWrite() afirma que deve ser chamadoModel.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 noupdateOne.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 },