While experimenting with Node.js for a coding game we are working on called Node Defender1 for the Ultimate Developer Conference, many asynchronous problems arose that we were unaccustomed to dealing with since we are primarily a PHP shop (read: synchronous). The examples covered in this post are specific to MongoDB, but the essence can be applied to any asynchronous process.
Each game is represented in MongoDB as a document containing various values for calculating the score. In order to get the highest value in various categories the following aggregate query needs to be run:
For a quick explanation:
sortercontrols which category by which we’re going to sort; descending in this case.
$projectis the projection of the aggregate we’d like MongoDB to return. In this case: the player’s name and the value of the category.
- Finally, the
$limitof 1, we just want the top value.
Async All the Things
Where does the promise come into play? With the async library, we can use a mapping to get the above aggregate for all required categories, execute in parallel, and return the results to one callback called the promise. In typical promise setups, there would be separate functions for a success, failure, and always. In our case, we’re going to setup our promise to receive all conditions and let that method determine how to handle the success and failure results.
We use the async “map” method to accomplish this. It allows us to pass an array of categories to the above aggregate, run the getTopCategory method against each one, compile the results, and then call our promise.
maparray contains the categories we want to run with the aggregate queries.
- We bind the
db(which is the connector to MongoDB) to the
getTopCategorymethod, which allows this method to have direct access to the
dbinstance without having to pass it in as a parameter.
- Finally, the promise anonymous method attached to the
Async.mapparameter gets the results (or errors) from all of the category aggregates and compiles them into a single list to be consumed by the calling method.
Using the “promise” pattern with the
async library, we can make concurrent asynchronous requests and return the results of asynchronous queries into one unified usable list back to the callee. This prevents our request from blocking other requests to Node because the event loop isn’t waiting on a series of synchronous queries to MongoDB.