Your problem in your code is that .find()
does not return a single mongoose document but rather an array of documents even if that array contains only a single item. You can correct this by calling .findOne()
or even .findById
which allows a much shorter form.
As mentioned earlier, this still has problems as there is no guarantee that the document on the server has not already been changed before you issue the .save() after making modifications. For this reason MongoDB provides an
.update()` method which will only make additional changes to the document via specified operators.
To add a new follower, you need to $push
the element onto the array:
.post(function(req, res) {
User.update(
{
"_id": req.decoded.id,
"following": { "$ne": req.params.user_id }
},
{ "$push": { "following": req.params.user_id }},
function(err, user) {
if (err) return res.send(err);
res.json({ message: "Successfully followed!"})
}
);
})
I actually check to see if that element is not present and then only update where that is the case. There is an $addToSet
operator that does this, but I would also suggest modifying your schema to include a "followingCount": and similar fields. These are useful for queries and it is not a simple matter to return the "length" of an array without reading the entire document:
var UserSchema = new Schema({
name: String,
username: { type: String, required: true, index: { unique: true }},
password: { type: String, required: true, select: false },
level: String,
followers: [{ type: Schema.Types.ObjectId, ref: 'User'}],
following: [{ type: Schema.Types.ObjectId, ref: 'User'}],
folloersCount: Number,
followingCount: Number
});
// And in later code
User.update(
{
"_id": req.decoded.id,
"following": { "$ne": req.params.user_id }
},
{
"$push": { "following": req.params.user_id }},
"$inc": { "followingCount": 1 }
},
function(err, user) {
if (err) return res.send(err);
res.json({ message: "Successfully followed!"})
}
);
})
That increases the counter value by using the $inc
operator. To do the reverse and remove a follower use $pull
User.update(
{
"_id": req.decoded.id,
"following": req.params.user_id
},
{
"$pull": { "following": req.params.user_id }},
"$inc": { "followingCount": -1 }
},
function(err, user) {
if (err) return res.send(err);
res.json({ message: "Successfully Un-followed :("})
}
);
})
That does what $addToSet
cannot and will not touch the documents when the query conditions are not met.
If you want the modified document in the response, use .findOneAndUpdate()
instead.
So just because you are using mongoose, don't forget that you are still basically using MongoDB. It is better to use the database operators to modify documents rather than do those modifications in code.
Read up on the query and update operators in the documentation. In fact read up on all of them as it is worthwhile learning.