Finding a MongoDB document by ObjectId with Mongoose

David Yeiser picture David Yeiser · Feb 21, 2013 · Viewed 33.4k times · Source

I am trying to update a document in MongoDB by finding it by the ObjectId. The work flow is as follows (this is for a blog).

  1. Create a new post in MongoDB by passing a title and body. The ObjectId is automatically created.
  2. Go to edit the post. It uses the ObjectId from the URL to grab it from the database and display it in the same new post form, just with the preexisting values.
  3. When the submit button is clicked I want to find the document by the ObjectId and update the values in the database with those in the post form.

Step 1 & 2 work fine, but step 3 doesn't seem to be working. It redirects to the page I need it to. But the database has not been updated. It's the same value as it was before.

Here's the relevant code for the update post portion:

app.js

app.post "/office/post/:id/update", ensureAuthenticated, routes.updatePost

routes/index.js

mongoose = require 'mongoose'
ObjectId = mongoose.Types.ObjectId

Post = require '../models/Post'

...

updatePost: function(req, res) {
  var o_id, the_id;

  the_id = req.params.id;
  console.log(the_id); // 510e05114e2fd6ce61000001

  o_id = ObjectId.fromString(the_id);
  console.log(o_id); // 510e05114e2fd6ce61000001

  return Post.update({
    "_id": ObjectId.fromString(the_id)
  }, {
    "title": "CHANGE"
  }, res.redirect("/office/edit/posts"));
}

I'm using Express and Mongoose.

This is also the post model if that helps:

(function() {
  var Post, Schema, mongoose;

  mongoose = require('mongoose');

  Schema = mongoose.Schema;

  Post = new Schema({
    title: String,
    subhead: String,
    body: String,
    publish_date: {
      type: Date,
      "default": Date.now
    },
    mod_date: {
      type: Date,
      "default": Date.now
    }
  });

  module.exports = mongoose.model('Post', Post);

}).call(this);

And here's the code for the edit blog post view:

app.js

app.get("/office/post/:id/edit", ensureAuthenticated, routes.editPost);

routes/index.js

editPost: function(req, res) {
  return Post.findById(req.params.id, function(err, post) {
    return res.render('edit-post', {
      post: post,
      title: post.title
    });
  });
}

Answer

Benoir picture Benoir · Feb 21, 2013

The problem is how you call update

return Post.update({
    "_id": ObjectId.fromString(the_id)
}, {
    "title": "CHANGE"
}, res.redirect("/office/edit/posts"));

The last argument will actually redirect the page, whereas update expects a function to be called when the update is complete

You should pass in

return Post.update({
    "_id": ObjectId.fromString(the_id)
}, {
    "title": "CHANGE"
}, function(err, model) {
    if (err) // handleerr

    res.redirect("/office/edit/posts"));
});

That way, we only redirect once the model is successfully updated