Trying to do a bulk upsert with Mongoose. What's the cleanest way to do this?

前端 未结 8 889
青春惊慌失措
青春惊慌失措 2020-12-05 10:13

I have a collection that holds documents that contains three fields: first_name, last_name, and age. I\'m trying to figure out what query in Mongoose I can use to do a bulk

8条回答
  •  甜味超标
    2020-12-05 10:56

    (mongoose@4.9.1, mongodb@3.4.2)

    After struggling with Mongoose API poor documentation, I solved the bulk upsert tweaking updateOne:{} operation in the bulkWrite() method.

    A couple of undocumented things to consider:

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

    The two key things here are incomplete API documentation issues (at the time of writing, at least):

    • 'upsert': true in each document. This is not documented in Mongoose API (), which often refers to node-mongodb-native driver. Looking at updateOne in this driver, you could think to add 'options':{'upsert': true}, but, no... that won't do. I also tried to add both cases to the bulkWrite(,[options],) argument, with no effect either.
    • GasStation.collection.bulkWrite(). Although Mongoose bulkWrite() method claims it should be called Model.bulkWrite() (in this case, GasStation.bulkWrite()), that will trigger MongoError: Unknown modifier: $__. So, Model.collection.bulkWrite() must be used.

    Additionally, note:

    • You don't need to use the $set mongo operator in the updateOne.update field, since mongoose handles it in case of upsert (see bulkWrite() comments in example).
    • Note that my unique index in the schema (needed for upsert to work properly) is defined as:

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

    Hope it helps.

    ==> EDIT: (Mongoose 5?)

    As noticed by @JustinSmith, the $set operator added by Mongoose doesn't seem to be working anymore. Maybe it's because of Mongoose 5?

    In any case, using $set explicitly should do:

    'update': { '$set': gasStation },
    

提交回复
热议问题