0

I have an API where I'm using Node/Express/Mongoose where I'm trying to call a function to grab IDs for a number of fields to populate my main function, which creates a profile card for a particular user.

I'm passing the 'owner_id' to my Profile method. Then I want to reference the returned fields in my main function, which is the Cards document.

But when I try to reference the results of the first call, I get an error saying the fields are undefined.

Here is my code:

router.route('/')

// CREATE INITIAL PROFILE AND ADD EMAILS, ADDRESSES, PHONES AND BUSINESSES ONE-BY-ONE
.post(function( req, res ){

  Profile.findOne({'owner_id': req.body.ownerId}, (err, profile) => {

  })


  var card = new Card();

  card.owner_id = req.body.ownerId;
  card.card_name = req.body.card_name;
  card.card_subtitle = req.body.card_subtitle;
  card.card_type = req.body.card_type;
  card.card_color = req.body.card_color;

  card.first_name.item = req.body.first_name ;
  card.first_name._id = profile.first_name._id;

  card.last_name.item = req.body.last_name;
  card.last_name._id = profile.last_name._id;

  card.company = req.body.company;
  card.title = req.body.title;

  card.initial.item = req.body.initial ;
  card.initial._id = profile.initial._id;

  card.birthday.item = req.body.birthday ;
  card.birthday._id = profile.birthday._id;

  card.highschool.item = req.body.highschool;
  card.highschool._id = profile.highschool._id;

  card.college.item = req.body.college ;
  card.college._id = profile.college._id;

  card.facebook.item = req.body.facebook;
  card.facebook._id = profile.facebook._id;

  card.linkedin.item = req.body.linkedin ;
  card.linkedin._id = profile.linkedin._id;

  card.linkedin_bus.item = req.body.linkedin_bus ;
  card.linkedin_bus._id = profile.linkedin_bus._id;

  card.twitter.item = req.body.twitter ;
  card.twitter._id = profile.twitter._id;

  card.google.item = req.body.google ;
  card.google._id = profile.google._id;

  card.pinterest.item = req.body.pinterest;
  card.pinterest._id = profile.pinterest._id;

  card.user_image.item = req.body.user_image;
  card.user_image._id = profile.user_image._id;


  card.phones = req.body.phones;
  card.emails = req.body.emails;
  card.addresses = req.body.addresses;
  card.businesses = req.body.businesses;


  card.save(function(err){
    if(err)
      res.send(err);
    res.send({message:'Card has been added'});
  });



});

Any feedback would be greatly appreciated.

cnak2
  • 1,711
  • 3
  • 28
  • 53

1 Answers1

1

The general problem

Profile.findOne is an asynchronous call. This basically means that it needs some time to get the profile. When it gets the profile, it will get passed to the callback function passed as a second parameter, and that callback function be executed.

Anything you run right after the Profile.findOne() call will be executed before the callback function. This is a really common issue with javascript, and you can get more insight about this in this really famous SO Q/A.

The solution

In your case, you can just move all your code that needs the profile to the callback function:

Profile.findOne({'owner_id': req.body.ownerId}, (err, profile) => {
  //this is the body of the callback function. It will be called some time after `findOne` is called.
  var card = new Card();

  card.owner_id = req.body.ownerId;
  card.card_name = req.body.card_name;
  card.card_subtitle = req.body.card_subtitle;
  card.card_type = req.body.card_type;
  card.card_color = req.body.card_color;

  card.first_name.item = req.body.first_name ;
  card.first_name._id = profile.first_name._id;

  card.last_name.item = req.body.last_name;
  card.last_name._id = profile.last_name._id;

  card.company = req.body.company;
  card.title = req.body.title;

  card.initial.item = req.body.initial ;
  card.initial._id = profile.initial._id;

  card.birthday.item = req.body.birthday ;
  card.birthday._id = profile.birthday._id;

  card.highschool.item = req.body.highschool;
  card.highschool._id = profile.highschool._id;

  card.college.item = req.body.college ;
  card.college._id = profile.college._id;

  card.facebook.item = req.body.facebook;
  card.facebook._id = profile.facebook._id;

  card.linkedin.item = req.body.linkedin ;
  card.linkedin._id = profile.linkedin._id;

  card.linkedin_bus.item = req.body.linkedin_bus ;
  card.linkedin_bus._id = profile.linkedin_bus._id;

  card.twitter.item = req.body.twitter ;
  card.twitter._id = profile.twitter._id;

  card.google.item = req.body.google ;
  card.google._id = profile.google._id;

  card.pinterest.item = req.body.pinterest;
  card.pinterest._id = profile.pinterest._id;

  card.user_image.item = req.body.user_image;
  card.user_image._id = profile.user_image._id;


  card.phones = req.body.phones;
  card.emails = req.body.emails;
  card.addresses = req.body.addresses;
  card.businesses = req.body.businesses;


  card.save(function(err){
    if(err)
      res.send(err);
    res.send({message:'Card has been added'});
  });
});
console.log(profile); // now, however, this line is executed immediately. At this point, profile is not even
// retrieved from the database. Even if the database call was somehow instant, here `profile` is not even in the scope.
Sergeon
  • 6,638
  • 2
  • 23
  • 43