2

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?

MMR
  • 2,599
  • 10
  • 48
  • 105
  • Would be great if you could use the [edit] link to your question to show us some context i.e. your `emp` model schema definition and an example data for that model or `emp` array. – chridam Jan 05 '17 at 14:33
  • Hi chridam edited my code. – MMR Jan 05 '17 at 14:40
  • I am able to update it but unable to increment arrau i.e v1.parents and v1.childrens – MMR Jan 05 '17 at 14:42

1 Answers1

1

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) });
});
chridam
  • 95,056
  • 21
  • 214
  • 219