Mongoose Docs and JSON.stringify

Mongoose JS

If you’re a JavaScript / Node.js developer that uses MongoDB, you’ll probably have already heard of Mongoose. It’s “elegant mongodb object modelling for node.js“ and saves you writing endless mappings, castings and validation. If you’ve not used it before check it out.

Mongoose documents / objects

The reason for this post isn’t just to tell you to go and play with Mongoose, I’m hoping people will find this post when the get stuck with something, like I did at the weekend.

The problem

I was happily coding away (slightly functionally) when I hit an interesting issue. Here’s a simplified version to help me explain:

The problem
1
2
3
4
5
6
7
8
var addProperty = λ.each(function(item) {
item.newProperty = "anything";
});
Items.find(function(err, items) {
addProperty(items);
console.log(JSON.stringify(items));
});

After adding the property “newProperty” to each of the items, I could then use the property without any issues - as you’d expect. As soon as I tried to JSON.stringify() the items, the new property was omitted! I spent about 15 minutes trying to debug and convince myself the world was broken until I realised why.

The reason

The “items” collection is actually an array of special Mongoose documents with various magical properties to help you save an item back again etc. This has it’s own toJSON function that is called when JSON.stringify is called, omitting any modifications to it’s structure since the last save or retrieval.

The solution

A quick Google led me to a StackOverflow answer that suggested messing with the Mongoose document, ewww. Fortunately I found a better solution that I posted as an answer.

The solution
1
2
3
4
Items.find().lean().exec(function(err, items) {
addProperty(items);
console.log(JSON.stringify(items));
});

By specifying the “lean“ option when performing a query, you will be returned a plain JavaScript object that behaves in the regular way. Provided you don’t need to save the item again (as this is not a MongooseDocument, no getters and setters are applied) you will be able to call JSON.stringify to your hearts content. It’s faster too, you should probably specify the lean option whenever you need objects for readonly purposes.

Mystery solved.