I have set up a user schema with mongoose which contains a subdocument "contacts". The subdocument "contacts" is a collection of contacts objects which contain the actual contact (reference to another user object) and some data which is related to the "friendship".
In my front-end application I can now manage the contacts by adding or removing users to my contact list. The front-end saves these changes as HTTP PUT requests to the server.
The PUT request contains the whole user object which more or less replaces the user object on the database. Unfortunately it is not possible to replace subdocument collection. You only can push new ones or remove them.
Here are the schemas:
var UserSchema = new Mongoose.Schema({
username: {
type: String,
index: { unique: true, sparse: true },
required: true, lowercase: true, trim: true
},
email: {
type: String,
index: { unique: true, sparse: true },
required: true, lowercase: true, trim: true
},
contacts: [ContactSchema]
});
var ContactSchema = new Mongoose.Schema({
user: {
ref: "User",
type: Mongoose.Schema.ObjectId
},
isContact: {
type: Boolean,
default: true
}
});
Currently I try to replace the contacts by removing all and adding the one in the request:
app.put('/me', loadUser, function(req, res, next) {
var user = req.user;
req.user.contacts.forEach(function(contact) {
req.body.contacts.forEach(function(contact) {
contact.remove();
});
});
req.body.contacts.forEach(function(contact) {
req.user.contacts.push(contact);
});
user.save(function(err, user) {
if (err) return next(err);
res.send(200);
});
});
Has somebody actually an better idea how I can update this subdocument collection to the state in the request?
You can use the _underscore library to filter (reject) the object you want to remove
Here an example how to remove something from an array without foreach.
var _und = require('underscore');
var array = [{_id:1, title:'object one'}, {_id:2, title:'object two'}, {_id:3, title: 'object three' }]
the_target = 'object two';
new_array = _und.reject(array, function(item){
return item.title === target;
})
The expected result should be:
=> [{_id:1, title:'object one'}, {_id:3, title:'object three'}]
If you know the id, even better.
All you have to do then is empty your subdocs by doing this:
var mytargetarray = [];
mytargetarray.push(new_array);
mytargetarray.save();
If you want to replace the whole subdoc array, why not just replacing them:
req.user.contacts = [];
req.user.contacts.push(req.body.contacts);
save and done.
Hope that helps a bit.
Just a hint, in mongodb you work with object arrays, you can simple replace every value:
// active data from database
user.name = 'test user';
// now just give the object a new value
user.name = 'new name';
// and save .. done
user.save();