How can I better optimise these DB queries/function flow?
1- First of all, you have a big function. You have to split it into some functions. Doing this you gain the possibility to test them with any testing framework.
2- Delegate the handle of error responses to the controller.
from -> return res.status(401).send(err);to (with Promises)-> deferred.reject(err); to (normal way) -> throw new Error(err);
3- You can use Promises to manage the asynchronous behaviour of node to clear the code.I created an example, maybe is not working at first time, feel free to fix the incorrent references. The User ref, the 'acceptfriend' method...
Gist: https://gist.github.com/aitoraznar/b7099ad88ead0cdab256
var Promise = require('bluebird');var _ = require('lodash');//var User = app.models.User;var ERRORS = { userNotFoundError: { code: 401, success: false, message: 'no user found with that id' }, friendRequestNotFoundError: { code: 401, success: false, message: 'friend request not found' }, friendNotFoundError: { code: 401, success: false, message: 'no friend found with that id' }}var SUCCESS_MESSAGES= { friendAddedSuccessfully: { success: true, message: 'friend succesfully added' }};var userDAO = { /* * */ getUserById: function(id) { var deferred = Promise.pending(); User.findById(id, function(err, user) { //error occured if (err) { err.code = 401; return deferred.reject(err); } //no user found if (!user) { return deferred.reject(ERRORS.userNotFoundError); } deferred.resolve(user); }); return deferred.promise; }, /* * Does the request exist? */ checkFriendRequest: function(user, friendId) { var deferred = Promise.pending(); if (userDAO.haveFriendRequestFrom(user, friendId)) { deferred.resolve(user, friendId); } else { return deferred.reject(ERRORS.friendRequestNotFoundError); } return deferred.promise; }, /* * */ haveFriendRequestFrom: function(user, friendId) { return _.any(user.social.friendRequests, {id: friendId }); }, /* * */ getFriend: function(user, friendId) { var deferred = Promise.pending(); userDAO.getUserById(friendId) .then(function(friend) { deferred.resolve(user, friend); }, function(error) { if (error === ERRORS.userNotFoundError) { // Then the error is friend not found // Override the error error = ERRORS.friendNotFoundError; } return deferred.reject(error); }); return deferred.promise; }, /* * */ makeFriendship: function(user, friend) { var deferred = Promise.pending(); //Pull the request from the friendRequests array user.social.friendRequests.pull(friend._id); //Add the friend user.social.friends.addToSet( { user_id: friend._id, name: friend.username, corp: 'n/a' } ); //Add the user to the friends list as well friend.social.friends.addToSet({ user_id: user._id, name: user.username, corp: 'n/a' }); //save the docs user.save(); friend.save(); // Return the new friendship var friendship = { user: user, friend:friend }; deferred.resolve(friendship); return deferred.promise; }, /* * */ friendRequestError: function(err) { var deferred = Promise.pending(); // Propagate de error deferred.reject(err); return deferred.promise; }, /* * */ friendRequest: function(userId, friendId) { var deferred = Promise.pending(); // Get user by ID userDAO.getUserById(userId) // Check if the user is able to add the friend .then(userDAO.checkFriendRequest, userDAO.friendRequestError) // Get the friend to add .then(userDAO.getFriend, userDAO.friendRequestError) // Make the friendship .then(userDAO.makeFriendship, userDAO.friendRequestError) // Response to the controller .then( function(friendship) { // Resolve with new friendship // This goes to 'success' function in controller deferred.resolve(friendship); }, function(error) { // This goes to 'error' function in controller deferred.reject(error); }) return deferred.promise; }};// Controllervar acceptfriend = function(req, res, next) { var userId = req.decoded._id; var friendId = req.params.id; userDAO.friendRequest(userId, friendId) .then(function(friendRequest) { console.log('---> SUCCESS'); //return success return res.status(200) .json(SUCCESS_MESSAGES.friendAddedSuccessfully); }, function(error) { console.error('---> ERROR', error); return res.status(error.code).json(error); });}
4- Create database indexes in the collection/table
Regards,Aitor