BACKGROUND
I have made a small site to run a tipping competition. I am using chartjs to draw garphs. I have made a function (createCjsDonutDataWinnerPickData) to format the data for the graph in to a format suitable for chartjs.
THE PROBLEM
For some reason the function (createCjsDonutDataWinnerPickData) is returning undefined. I think it is due to the "return" returning before the function has finished processing.
I am calling the function in two places. The first is a test before the page is rendered and the second time is when rendering the page.
Extract from page rendering function
Point.findOne({user:req.user.id, competition:comp.id, fixture:fixture.id}).exec(function (err, points){
        if (err) {console.log('ERR: fixtures pick page on COMP lookup')}
        else {
            console.log('TEST FUNCTION');
            console.log(createCjsDonutDataWinnerPickData(fixture._id,comp._id,createIdLookup(teams)));
            res.render('fixturePick.ejs', {
                user : req.user, // get the user out of session and pass to template
                fixture: fixture,
                pick: pick,
                teams: createIdLookup(teams),
                draw: draw,
                round: round,
                competition: comp,
                points: points,
                gWinnerPickGraph: JSON.stringify( createCjsDonutDataWinnerPickData(fixture._id,comp._id,createIdLookup(teams)) ),                                   
                successMsg: req.flash('successMsg'),
                dangerMsg: req.flash('dangerMsg'),
                warningMsg: req.flash('warningMsg')
            });
        }
    });
The function createCjsDonutDataWinnerPickData
function createCjsDonutDataWinnerPickData(fixtureID,competitionID,teamLookup){
    var Statistic = require('../app/models/statistic');
    var Fixture = require('../app/models/fixture');
    var async = require('async');
    try {
        async.waterfall([
            function(cb_ReturnData){
                var chartData =[];
                Statistic.findOne({fixture:fixtureID, competition:competitionID,type:'winnerPickNumber'}).populate('fixture').exec(function (err,statData){
                    if (err) {console.log('ERROR in preparing data for graph');throw (err)}
                    else {
                        async.each(statData.data, function(dataPoint,cb_PrepData){
                            var sliceData = {};
                            if (statData.fixture.homeTeam._id == dataPoint.teamID){
                                //console.log('Found data for home team')
                                sliceData = {value: dataPoint.number, color:"rgba(151,187,205,0.5)", highlight: "rgba(151,187,205,0.75)", label:teamLookup[dataPoint.teamID].name };
                            }
                            else
                            {
                                //console.log('Found data for away team')
                                sliceData = {value: dataPoint.number, color:"rgba(220,220,220,0.5)", highlight: "rgba(220,220,220,0.75)", label:teamLookup[dataPoint.teamID].name };
                            }
                            //console.log('Pusihgin slice data to data')
                            chartData.push(sliceData);
                            cb_PrepData();
                        }, function(err){
                            if (err) {
                                console.log('ERROR in creating data for WinnerPickGraph');
                                cb_ReturnData(err);
                            }
                            else {
                                //console.log('CHART DATA IN INNER ASYNC');
                                //console.log(chartData);
                                cb_ReturnData(null, chartData);
                            }
                        });
                    }
                });
            }
            ],function(err,chartData){
                if (err) {console.log('ERROR in preparing return data')}
                else {
                    console.log('HERE IS THE FINAL RETURN');
                    console.log(chartData);
                    return (chartData);
                }
            });
     }
    catch (err){
        //probably end up here because there is no points History Data
        console.log('threw erro returning undefined');
        return undefined;
    }
}
Console output
GET /fixturePick?competition=542a5ffa736e3e35532f2d24&fixture=542c9ae12367c9209a739150 302 5.532 ms - 58
PATH: /fixturePick?competition=542a5ffa736e3e35532f2d24&fixture=542c9ae12367c9209a739150
GET / 200 11.291 ms - 1515
GET /images/grassBackground.jpg 200 5.533 ms - 145369
POST /login 302 459.431 ms - 228
TEST FUNCTION
undefined
GET /fixturePick?competition=542a5ffa736e3e35532f2d24&fixture=542c9ae12367c9209a739150 200 1609.303 ms - 4984
GET /images/team/logo/sm/53fc6399b918a6b661d423b4.png 200 2.720 ms - 15747
HERE IS THE FINAL RETURN
[ { value: 1,
    color: 'rgba(220,220,220,0.5)',
    highlight: 'rgba(220,220,220,0.75)',
    label: 'Melbourne Victory' },
  { value: 2,
    color: 'rgba(220,220,220,0.5)',
    highlight: 'rgba(220,220,220,0.75)',
    label: 'Western Sydney Wanderers' } ]
HERE IS THE FINAL RETURN
[ { value: 1,
    color: 'rgba(220,220,220,0.5)',
    highlight: 'rgba(220,220,220,0.75)',
    label: 'Melbourne Victory' },
  { value: 2,
    color: 'rgba(220,220,220,0.5)',
    highlight: 'rgba(220,220,220,0.75)',
    label: 'Western Sydney Wanderers' } ]
GET /images/team/logo/sm/53fc6399b918a6b661d423b5.png 200 2.368 ms - 13144
GET /images/none.png 200 1.857 ms - 195
I may have overcomplicated this with async.foreach and async.waterfall but I was running out of ideas as to why the function keeps returning undefined.
 
    