modernator modernator - 5 months ago 35
Node.js Question

MongoDB updating embedded document isn't working

I'm trying to update embedded document, but it is not working. This is what documents look like:

{
"_id" : ObjectId("577c71735d35de6371388efc"),
"category" : "A",
"title" : "Test",
"content" : "Test",
"tags" : "test",
"comments" : [
{
"_id" : ObjectId("57811681010bd12923eda0ca"),
"author" : "creator",
"email" : "creator@example.com",
"text" : "helloworld!"
},
{
"_id" : ObjectId("57811b17b667676126bde94e"),
"author" : "creator",
"email" : "creator@example.com",
"text" : "helloworld2!"
}
],
"createdAt" : ...,
"updatedAt" : ...
}


you can see the comments field is embedded document that contains comments. I want to update specific comment, so I made query like this(node.js):

db.update('posts', {
_id: new ObjectID(postId), // ID of the post
comments: {
$elemMatch: {
_id: new ObjectId(commentId)
}
}
}, {
$set: {
"comments.$.author": newComment.author,
"comments.$.email": newComment.email,
"comments.$.text": newComment.text,
"comments.$.updatedAt": new Date()
}
}) ...


when I run this query, no error was shown but update wasn't applied. I tried this query too:

{
_id: new ObjectId(postId),
"comments._id": new ObjectId(commentId)
}


but not worked either. Am I missing something? I'm using Mongo v3.2.7.

Answer

Please try the below code. I think the "ObjectId" (i.e. case) should be the problem. Just check how you defined the object id and keep it consistent in the two places that you have used (i.e. posts _id and comments _id -> both places).

ObjectID = require('mongodb').ObjectID

The below code works fine for me. Basically, your query seems to be correct.

var Db = require('mongodb').Db, MongoClient = require('mongodb').MongoClient, Server = require('mongodb').Server, ReplSetServers = require('mongodb').ReplSetServers, ObjectID = require('mongodb').ObjectID, Binary = require('mongodb').Binary, GridStore = require('mongodb').GridStore, Grid = require('mongodb').Grid, Code = require('mongodb').Code, assert = require('assert');

var db = new Db('localhost', new Server('localhost', 27017));
db.open(function(err, db) {
    var collection = db.collection("posts");

    var postId = '577c71735d35de6371388efc';
    var commentId = '57811681010bd12923eda0ca';

    var query = {
        _id : new ObjectID(postId), 
        comments : {
            $elemMatch : {
                _id : new ObjectID(commentId)
            }
        }
    };

    collection.update(query, {
        $set : {
            "comments.$.author" : "new author",
            "comments.$.email" : "newemail@gmail.com",
            "comments.$.text" : "new email updated",
            "comments.$.updatedAt" : new Date()
        }
    }, {
        multi : false
    }, function(err, item) {        
        assert.equal(null, err);
        console.log("comments updated ..." + JSON.stringify(item));
    });

});