Cedric Bongaerts Cedric Bongaerts - 6 months ago 135
Node.js Question

Mongodb | mongoose: Remove from nested document with $pull

I have the following two models:

Capture

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var captureSchema = Schema({
type: String,
birdname: {type: String, required: true},
place: String,
note: String,
userId: String,
author: String,
picture: Schema.Types.Mixed,
created_at: Date,
comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment'}],
});

module.exports = mongoose.model('Capture', captureSchema);


Comment

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var commentSchema = Schema({
body: String,
userId: String,
author: String,
created_at: Date,
capture: [{ type: Schema.Types.ObjectId, ref: 'Capture'}]
});

module.exports = mongoose.model('Comment', commentSchema);


My goal is to remove a comment from a capture but I can't seem to figure out how to remove the ref 'id' from capture once I have deleted a comment.

Currently I'm using the following the remove a comment:

var Comment = require('../models/comment');
var Capture = require('../models/capture');

...

router.delete('/comments/:id', function(req, res){
Comment.remove({_id: req.params.id}, function(err){
res.json({result: err ? 'error' : 'ok'});
console.log('comment removed');
});

//DOES NOT WORK ---> Need assistance with $pull
Capture.update({_id: Capture.comments._id}, {
$pull : {'comments' : req.params.id}}, function(err, data) {
if(err) throw err;
res.json(
});
});


But for some reason, only my comment gets deleted, but the reference stays on my capture as followed (example):

{
"_id": "574b640e39c34ad806b7eab6",
"created_at": "2016-05-29T21:50:06.772Z",
"picture": "https://cdn.filepicker.io/api/file/C9Z73CQwCiFP8pdB5W7A",
"author": "Cedric Bongaerts",
"userId": "facebook|10153403872376529",
"place": "Afrika",
"birdname": "Mountain Serpent Eagle",
"type": "ok",
"__v": 14,
"comments": [
"574cbfa6ab7e2b44184584df",
"574cbfa6ab7e2b4682452fss",
"574cb61vdz422b57584d417s",
]
}


While my comments are empty (been deleted).

Edit:
An extra thing to mention:
When I get the capture by 'id'
/api/captures/:capture
, it does show that the comment is deleted.. It only stays when viewing the full captures list
/api/captures

Answer

You need to get the comment document you're removing so that you can access its capture field that contains the _id of the Capture document to remove the comment reference from. The easiest way to do that is to use findByIdAndRemove instead of just remove when removing the comment:

Comment.findByIdAndRemove(req.params.id, function(err, comment){
    if (comment) {
        Capture.update({_id: comment.capture}, {
                $pull : {comments: req.params.id}
            }, function(err, data) { ... });
    }
});

Note that this assumes that capture is not an array (as discussed in the comments), and is defined like this instead:

capture: { type: Schema.Types.ObjectId, ref: 'Capture'}