Question

I'm trying to query two separate collections using MongoJS (node.js mongodb wrapper) to build an array of objects that I'll then render with my view using EJS.

The issue I've run into seems to do with scoping.

function getTeamMembers(projectID){

        var members = []; //<-- Instantiate the array of objects I want to return

        Projects.findOne(
            { _id : mongojs.ObjectId(projectID) },
            function(error, result){

                /// Loop through the team to get the member's data
                /// and push it on the members array

                var team = result.team; //<-- This is an array of objects

                for(var i = 0; i < team.length; i++){

                    members[i] = {};
                    members[i].accountID = team[i].accountID;
                    members[i].status = team[i].status;

                    Accounts.findOne(
                            { _id : mongojs.ObjectId(team[i].accountID) },
                            function(error, doc){

                                /// The following line produces the error:
                                /// 'Cannot set property name of undefined' 
                                members[i].name = doc.name;

                            }
                    );

                }

                response.send(members);

            }
        );

    }

I believe that I'm instantiating the members[] array in the correct spot to make it available to any child functions, but I'm still getting this error:

TypeError: Cannot set property 'name' of undefined

Was it helpful?

Solution

You need to create a scope that captures the current value of i because by the time your findOne() callbacks execute, the loop has already long been finished and i=team.length. You're also sending the response before any of the names are filled in. You may want to use the async module to handle this for you.

This:

for(var i = 0; i < team.length; i++){

    members[i] = {};
    members[i].accountID = team[i].accountID;
    members[i].status = team[i].status;

    Accounts.findOne(
            { _id : mongojs.ObjectId(team[i].accountID) },
            function(error, doc){

                /// The following line produces the error:
                /// 'Cannot set property name of undefined' 
                members[i].name = doc.name;

            }
    );

}

response.send(members);

Becomes:

var async = require('async');

// ....

async.each(team, function(teamItem, callback) {
  var member = {
    accountID: teamItem.accountID,
    status: teamItem.status,
    name: ''
  };
  members.push(member);

  Accounts.findOne(
          { _id : mongojs.ObjectId(member.accountID) },
          function(error, doc) {
            if (error)
              callback(error);
            else {
              member.name = doc.name;
              callback();
            }
          }
  );
}, function(err) {
  if (err)
    response.send(500, err.toString());
  else
    response.send(members);
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top