Reputation: 3009
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?
Upvotes: 2
Views: 1255
Reputation: 61
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.
Upvotes: 0
Reputation: 103305
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) });
});
Upvotes: 1