Bulk upsert in MongoDB using mongoose

后端 未结 6 625
自闭症患者
自闭症患者 2020-11-27 04:53

Is there any option to perform bulk upserts with mongoose? So basically having an array and insert each element if it not exists or update it if it exists? (I am using custo

6条回答
  •  迷失自我
    2020-11-27 05:22

    You don't need to manage limit (1000) as @neil-lunn suggested. Mongoose does this already. I used his great answer as a basis for this complete Promise-based implementation & example:

    var Promise = require('bluebird');
    var mongoose = require('mongoose');
    
    var Show = mongoose.model('Show', {
      "id": Number,
      "title": String,
      "provider":  {'type':String, 'default':'eztv'}
    });
    
    /**
     * Atomic connect Promise - not sure if I need this, might be in mongoose already..
     * @return {Priomise}
     */
    function connect(uri, options){
      return new Promise(function(resolve, reject){
        mongoose.connect(uri, options, function(err){
          if (err) return reject(err);
          resolve(mongoose.connection);
        });
      });
    }
    
    /**
     * Bulk-upsert an array of records
     * @param  {Array}    records  List of records to update
     * @param  {Model}    Model    Mongoose model to update
     * @param  {Object}   match    Database field to match
     * @return {Promise}  always resolves a BulkWriteResult
     */
    function save(records, Model, match){
      match = match || 'id';
      return new Promise(function(resolve, reject){
        var bulk = Model.collection.initializeUnorderedBulkOp();
        records.forEach(function(record){
          var query = {};
          query[match] = record[match];
          bulk.find(query).upsert().updateOne( record );
        });
        bulk.execute(function(err, bulkres){
            if (err) return reject(err);
            resolve(bulkres);
        });
      });
    }
    
    /**
     * Map function for EZTV-to-Show
     * @param  {Object} show EZTV show
     * @return {Object}      Mongoose Show object
     */
    function mapEZ(show){
      return {
        title: show.title,
        id: Number(show.id),
        provider: 'eztv'
      };
    }
    
    // if you are  not using EZTV, put shows in here
    var shows = []; // giant array of {id: X, title: "X"}
    
    // var eztv = require('eztv');
    // eztv.getShows({}, function(err, shows){
    //   if(err) return console.log('EZ Error:', err);
    
    //   var shows = shows.map(mapEZ);
      console.log('found', shows.length, 'shows.');
      connect('mongodb://localhost/tv', {}).then(function(db){
        save(shows, Show).then(function(bulkRes){
          console.log('Bulk complete.', bulkRes);
          db.close();
        }, function(err){
            console.log('Bulk Error:', err);
            db.close();
        });
      }, function(err){
        console.log('DB Error:', err);
      });
    
    // });
    

    This has the bonus of closing the connection when it's done, displaying any errors if you care, but ignoring them if not (error callbacks in Promises are optional.) It's also very fast. Just leaving this here to share my findings. You can uncomment the eztv stuff if you want to save all eztv shows to a database, as an example.

提交回复
热议问题