Search code examples
node.jsmongodbfindandmodify

findAndModify usage in node.js/MongoDb


I have a collection which shows a list of users with their favorite movies. Here is a sample dataset ...

{
        "_id" : ObjectId("545c08dcc4d2b8a0243dd4db"),
        "mail" : "mickey@mouse.com",
        "name" : "Mickey Mouse",
        "favorite_movies" : [
                {
                        "name" : "The Green Mile",
                        "Year" : "1992"
                },
                {
                        "name" : "Raging Bull",
                        "Year" : "1980"
                }
        ],
        "watched_movies" : [
                {
                        "name" : "The Green Mile",
                        "Year" : "1992"
                },
                {
                        "name" : "Jaws",
                        "Year" : "1976"
                }              
        ]
}

Now given _id 545c08dcc4d2b8a0243dd4db and a movie

{
   "name" : "InterStellar",
   "Year" : "2014"
}

and if I need to add this to the watched_movies, in Node.js/MongoDB, I believe the only way is to

  1. Find the document using Find
  2. Do a findAndModify on the found document by appending to the watched_movies array.

Step #2 is based on example here http://mongodb.github.io/node-mongodb-native/markdown-docs/insert.html

Is there a better way to do this ? Specifically can I avoid the step#1 ?

Here is how I'm doing step#2. But I'm forced to do step#1 to get the "watched_movies" element and then append the new movie to it to construct the movielist

//try to update
collection.findAndModify(
{'_id':new BSON.ObjectID(id)}, //query
[['_id','asc']], //sort order
{$set: {"watched_movies": movielist}}, //replacement
{new: true}, //options
function(err, newObject){
   if(err) {
     console.warn(err.message);
   } else {
     console.log("Updated !! " + JSON.stringify(newObject));
     res.send(object);
   }
 });

I am also open to suggestions on improving this schema design.


Solution

  • You can do this with a single findAnyModify call by using the $push or $addToSet array operator to directly add the new movie to the watched_movies array:

    var movie = {
       "name" : "InterStellar",
       "Year" : "2014"
    };
    
    collection.findAndModify(
      {'_id':new BSON.ObjectID(id)},
      [['_id','asc']],
      {$addToSet: {"watched_movies": movie}},
      {new: true},
      function(err, newObject){
         if(err) {
           console.warn(err.message);
         } else {
           console.log("Updated !! " + JSON.stringify(newObject));
           res.send(newObject);
         }
      });