3

How can I modify an object returned by a Mongoose query?

Assume we have the following schema:

var S = new mongoose.Schema( { 'name': String, 'field': String } );

I do the following query and modification to the result:

var retrieve = function(name, callback) {
    S.findOne({ name: name }).exec(function (err, obj) {
      if (err) return handleError(err);
      obj['field'] = 'blah';
      callback(obj);
    });
}

The obj.field will not contain blah but the original value returned by the query, as if it was read-only. What is going on?

Note: my environment is Node.js, Express, Mongoose and MongoDB

Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
Ze Jibe
  • 989
  • 2
  • 11
  • 29
  • possible duplicate of [Why can't you modify the data returned by a Mongoose Query (ex: findById)](http://stackoverflow.com/questions/14504385/why-cant-you-modify-the-data-returned-by-a-mongoose-query-ex-findbyid) – steampowered Aug 21 '15 at 03:00

2 Answers2

3

Note: This is an edit, my original answer was rather different

So this is a little confusing but Mongoose returns MongooseDocument objects and not plain JSON objects. So use the .lean() method on obj which will turn it into JSON, and from there you start altering it as you wish.

With thanks to Ze Jibe.

Niall Paterson
  • 3,580
  • 3
  • 29
  • 37
  • Thanks Niall, but does not fix the issue: `obj`still unchanged. I should also precise that I don't want to update the object in the DB, but simply use a copy of it that I can modify for other purposes. I've tried copying the `obj` to `cpy`and modify `cpy` but I'm left with the same problem, that `cpy`seems also to be read-only – Ze Jibe Mar 27 '13 at 22:57
  • hmm is there any reason you went with .exec over `S.findOne({name: name}, function (err,obj) { .. })`? – Niall Paterson Mar 27 '13 at 23:02
  • hmm odd, I'm literally just throwing things out there now. what happens where ever callback(obj) is? like is it 'read-only' then? Sounds very odd that it'd be read only. you've me intrigued – Niall Paterson Mar 27 '13 at 23:07
  • callback(obj) is a `res.send(obj)`, so I can see in my browser what the content of `obj` is. I've also put `console.log()` around the `obj['field'] = 'blah'` command, and both before and after the command the `obj` content is the same (as printed in the console). I'm clueless... – Ze Jibe Mar 27 '13 at 23:11
  • you know where you have res.send(obj)? Could you throw a quick `obj['field'] = 'blah';` just to check if its okay then? Might give a hint.. – Niall Paterson Mar 27 '13 at 23:13
2

The doc object returned from mongoose is somehow read only. To get a writeable object from it you must run:

var writeableObject = doc.toObject()
writeableObject['field'] = 'blah'
res.send(writeableObject)

Scroll down to "Transform" in the mongoose documentation to read more: link

Pylinux
  • 11,278
  • 4
  • 60
  • 67