I might be doing it wrong with Mongoose after using it for a while. I find it difficult to read when you have too much callbacks, eg:
I want to find a document and update it. I need to find it first, then the update
will be inside the callback of the findOne
.
var sam = new Character({ name: 'Sam', inventory: {}});
Character.findOne({ name: 'Sam' }, function(err, character) {
console.log(character);
// now I want to update it.
character.update({... }, function(err, characterID) {
// now I want to know the size of the document after the update.
Character.findOne({ _id: characterID }, function(err, character) {
// Now update it again....
});
});
});
It ends up a spaghetti code eventually!
You see what I mean?
Any ideas how to do it better?
Or mongodb native is better without all these callbacks?
EDIT:
Character.findOne({...}, function(err, character) {
return character.update(...);
}).select("-field1 -field2").then(function(data) {
//
}).catch(function(error) {
// Handle any error from all above steps
}).done();
Error:
TypeError: Character.findOne(...).select(...).then(...).catch(...).done is not a function
You have now discovered "callback hell". This is not limited to Mongoose, or Mongo, but is part of all Node.js programming, and don't feel alone. All of us have had to deal with it.
In MongoDB (or any data event with most DB's) the problem is the chain of events taking place and the need to catch the errors or make the program wait for the step to be completed.
Promises can be either a async or sync solution to callbacks. You can use bluebird to wrap your events in Promises. This requires an understanding of the
.then
andreturn
constructs. However in essence what you do is say: "Do step 1 and then do step 2." (and so on). Remember though, depending upon the coding you still have to catch errors, and you can easily turn your entire code into sync which is not an ideal situation in Node.js. However, it will solve the "callback hell" of Mongo connections. What I am saying is try not to fall into the habit of putting all your code into the .then --> return paradigm, but only those places where it really is required.The new MongoDB Node Driver (v. 2.2.5) is much better than the previous. Mongo has instantiated ECMAScript 6 if you include the co module, which supplies the yield and return events (read below about async/await, as it is essentially the same thing). This is lightyears ahead of what the driver was until now. This will help you get out of "callback hell" with your Mongo connections and CRUD operations.
So to get out of "callback hell" the normal response is to use promises.
To make matters a bit more complicated, the new Node.js (not the LTS) but versions above 7.7XX which are not yet official use a long awaited async/await structure from ES7. This should keep your code async with promises. An outside article on this can be seen here.
Depending upon your app and your requirements, try the use of Promises, or you can simply use the new MongoDB driver with co for Mongo. As to which module to use, be it bluebird, co, or something else, that is up to you. When Node.js officially releases the async/await and it works as advertised, it would be a good time to use that model instead of callbacks.
Since Mongoose supports promises (documented here), you can rewrite your code to this:
There's not need to wrap each function you use using an external promise library. You may get a warning about Mongoose using a deprecated promise library, which is easily fixed by including this at the top of your code:
Documented here.
However, you can replace the entire promise chain above with a single command:
Documented here.
You can use chaining of q promise in nodejs