简体   繁体   中英

How can I better optimise these DB queries/function flow?

I've turned my hand from game dev to writing a supporting back-end. Thus far everything seems to work out but when i got to writing a friend system i ran into this function flow which seemed very dirty to me. And i'm certain i'm just hacking it together at this point. Any node.js wizards about to tell me how I can improve this?

Fairly certain i should be caching player lookups in Redis as well.

acceptfriend: function(req, res){
    //Find our user
    User.findById( req.decoded._id, function(err, user){
        //error occured
        if(err){
            return res.status(401).send(err);
        }
        //no user found
        if(!user){
            return res.status(401).json({
                succes: false,
                message: 'no user found with that id'
            } );
        }
        //Does the request exist?
        if( !_.any( user.social.friendRequests, {id: req.params.id} ) ){
            return res.status(401).json( {
                succes: false,
                message: 'friend request not found'
            } );
        }
        //find the user that belongs to the request
        User.findById( req.params.id, function(err, friend){
            //error occured
            if(err){
                return res.send(err);
            }
            //user doesnt exist
            if(!friend){
                return res.status(401).json({
                    succes: false,
                    message: 'no user found with that id'
                } );
            }
            //Pull the request from the friendRequests array
            user.social.friendRequests.pull( req.params.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 success
        return res.status(200).json({
            success: true,
            message: 'friend succesfully added'
        });
    } );
}

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; } }; // Controller var 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM