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,869
  • 13
  • 56
  • 110
  • 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

2 Answers2

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
  • 100,957
  • 23
  • 236
  • 235
0

Very important guys, that you keep in mind that not all updating mechanisms respect the model/schema. Like updateOne does not. Meaning, you can "update" a document to absolutely anything by any simple update. That will then cause problems as your next query to that data will expect it in a certain well defined way, else break the code/crash. So be mindful whether your method follows the schema and does not break it. Such bugs can be extremely painful and difficult to find.

Yash Gada
  • 41
  • 4
  • Was it Chatgpt ?? – Rohit Gupta Apr 16 '23 at 02:46
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/34191559) – Rohit Gupta Apr 16 '23 at 02:46