Search code examples
node.jsmongodbmongoosemean-stack

How to update a record in mongoose


I am trying to update a field of a record in loop and note that the field is an array and my code is as below,

  Employeehierarchy = mongoose.model('Employeehierarchy'),
  function (done) {
      var ObjectId = require('mongoose').Types.ObjectId; 
      var item = {'childrens':{$in:[ ObjectId(employee.manager)]}};
      Employeehierarchy.find(item).exec(function (err, employeehierarchy) {
        if (err) {
          return res.status(400).send({ message: errorHandler.getErrorMessage(err) });
        } else {
          if (employeehierarchy && employeehierarchy.length > 0) {
              employeehierarchy.forEach(function (v1, i1) {
              v1.parents = employee._id;
              employeehierarchy = _.extend(employeehierarchy, v1);
              employeehierarchy.save(function (err) {
              });
            }); done();
          } else {
            done();
          }
        }
      });
    },

my schema,

var EmployeehierarchySchema = new Schema({
  name: {
    type: String,
    default: ''
  },
  parents: {
    type: Array,
    default: ''
  },
  childrens: {
    type: Array,
    default: ''
  },
});

I dont know where I went wrong, can any one help me?


Solution

  • You could use the Bulk Write Operations API to update your models. But in order to use the underlying bulk operations API, you should access it via the .collection property from the mongoose model and before using the API, wait for mongoose to successfully connect to the db since Mongoose doesn't really support the "initializeOrderedBulkOp()" function yet, because it doesn't work with mongoose's internal buffering system.

    You can implement something like the following which uses Promises to handle the async nature of the bulk API in node.js.

    Model declarations

    var mongoose = require('mongoose'),
        express = require('express'),
        Promise = require('bluebird'),
        Schema = mongoose.Schema;
    
    var employeeHierarchySchema = new Schema({
        name: {
            type: String,
            default: ''
        },
        parents: {
            type: Array,
            default: ''
        },
        childrens: {
            type: Array,
            default: ''
        }
    });
    
    var Employeehierarchy = mongoose.model('Employeehierarchy', employeeHierarchySchema);    
    

    Function to carry out the bulk updates using Promises:

    function bulkUpdate(Model, query){    
        return new Promise(function(resolve, reject){
            var ops = [],
                collection = Model.collection;
    
            Model.find(query).lean().exec(function (err, docs) {
                if (err) return reject(err);
    
                docs.forEach(function (doc){
                    ops.push({
                        "updateOne": {
                            "filter": { "_id": doc._id },
                            "update": {
                                "$push": { "parents": doc._id }
                            }
                        }
                    });
    
                    if (ops.length === 500) {
                        collection.bulkWrite(ops, function(err, result) {
                            if (err) return reject(err);                        
                            ops = [];
                            resolve(result);
                        });
                    }                       
                });     
    
                if (ops.length > 0) {            
                    collection.bulkWrite(ops, function(err, result) {
                        if (err) return reject(err);
                        resolve(result);
                    });         
                }           
            });     
        });
    }
    

    Alternative function for older MongoDB versions that use initializeUnorderedBulkOp()

    function bulkUpdate(Model, query){    
        return new Promise(function(resolve, reject){
            var bulk = Model.collection.initializeUnorderedBulkOp(),
                counter = 0;
    
            Model.find(query).lean().exec(function (err, docs) {
                if (err) return reject(err);
    
                docs.forEach(function (doc){
                    counter++;
    
                    bulk.find({ "_id": doc._id }).updateOne({
                        "$push": { "parents": doc._id }
                    });
    
                    if (counter % 500 == 0 ) {
                        bulk.execute(function(err, result) {
                            if (err) return reject(err);                        
                            bulk = Model.collection.initializeUnorderedBulkOp();                        
                            resolve(result);
                        });
                    }                       
                });     
    
                if (counter % 500 != 0 ) {            
                    bulkUpdateOps.execute(function(err, result) {
                        if (err) return reject(err);
                        resolve(result);
                    });         
                }           
            });     
        });
    }
    

    Function to connect to MongoDB

    function connect(uri, options){
        return new Promise(function(resolve, reject){
            mongoose.connect(uri, options, function(err){
                if (err) return reject(err);
                resolve(mongoose.connection);
            });
        });
    }   
    

    Run the bulk updates on connection

    connect('mongodb://localhost/yourdb', {}).then(function(db){
        var query = { "childrens": employee.manager };
        bulkUpdate(Employeehierarchy, query).then(function(res){
            console.log('Bulk update complete.', res);      
        }, function(err){
            res.status(400).send({ message: errorHandler.getErrorMessage(err) });
            db.close();
        });
    }, function(err){
        res.status(400).send({ message: errorHandler.getErrorMessage(err) });
    });