Link to home
Start Free TrialLog in
Avatar of Bruce Gust
Bruce GustFlag for United States of America

asked on

Profile.save is not a function. What am I doing wrong?

Here's my code in full:

require("dotenv").config();
const { validationResult } = require("express-validator/check");
const mongoose = require("mongoose");
const Profile = require("../models/profile");
const ClientId = process.env.CLIENTID;
const Secret = process.env.SECRET;
const Callback = process.env.CALLBACK;

//this is the empID you're getting from AHA
const empID = 7747;

//get today's date
let date_ob = new Date();

// current date
// adjust 0 before single digit date
let date = ("0" + date_ob.getDate()).slice(-2);

// current month
let month = ("0" + (date_ob.getMonth() + 1)).slice(-2);

// current year
let year = date_ob.getFullYear();

// prints date in YYYY-MM-DD format
let today = year + "-" + month + "-" + date;

const FitbitApiClient = require("fitbit-node");
const client = new FitbitApiClient({
  clientId: ClientId, //client_id
  clientSecret: Secret, //client secret
  apiVersion: "1.2" // 1.2 is the default
});

exports.getCallback = (req, res, next) => {
  const yesterday_raw = new Date(new Date().setDate(new Date().getDate() - 1));
  const yesterday = yesterday_raw.toISOString().slice(0, 10);

  client.getAccessToken(req.query.code, Callback).then(result => {
    var requests = [
      client.get("/profile.json", result.access_token), //0
      client.get("/activities/date/today.json", result.access_token), //1
      //client.get("/sleep/date/" + yesterday + ".json", result.access_token), //2
      client.get("/sleep/date/today.json", result.access_token), //2
      //client.get("/sleep/date/2019-11-05.json", result.access_token), //2
      client.get(
        "/foods/log/caloriesIn/date/today/1d.json",
        result.access_token
      ), //dailly intake of calories 3
      client.get("/foods/log/water/date/today.json", result.access_token), // 4 this works!
      client.get("/activities/heart/date/today/1d.json", result.access_token), //5
      client.get("/body/log/weight/goal.json", result.access_token, undefined, {
        "Accept-Language": "en_US"
      }), //6
      client.get("/activities/date/" + yesterday + ".json", result.access_token) //7
    ];
    Promise.all(requests)
      .then(data => {
        //profile info
        const firstName = data[0][0].user.firstName; //0
        const lastName = data[0][0].user.lastName; //0
        const dateOfBirth = data[0][0].user.dateOfBirth; //0
        const gender = data[0][0].user.gender; //0

        //calorie goals - to be burned including BMR
        const calories_goal = JSON.stringify(data[1][0]["goals"].calories); //1 calorie goal
        const massive_total = JSON.stringify(data[1][0].summary.calories.total); //1 big calorie total
        const BMR = JSON.stringify(data[1][0].summary.calories.bmr); //1 - BMR
        const calories_burned = massive_total - BMR;

        //sleep
        const slumber = JSON.stringify(
          data[2][0].summary.totalMinutesAsleep / 60
        ); //2 total sleep hours
        const sleep = JSON.stringify(Math.round(slumber * 10) / 10);

        const rem_sleep = data[2][0]["sleep"].length
          ? data[2][0]["summary"].stages.rem
          : 0; //minutes in deep REM sleep

        //nutrition
        const eating = JSON.stringify(
          data[3][0]["foods-log-caloriesIn"][0].value
        ); //3
        const caloriesIn = eating.replace(/\"/g, "");

        //water
        const water = JSON.stringify(data[4][0].summary.water);

        //heart rate
        const rhr = JSON.stringify(
          data[5][0]["activities-heart"][0].value.restingHeartRate
        );

        //body weight goal
        //res.setHeader('Accept-Language', 'en_US')
        const startWeight = JSON.stringify(data[6][0].goal.startWeight);
        const targetWeight = JSON.stringify(data[6][0].goal.weight);
        //res.send(targetWeight);

        //steps
        const totalStepsYesterday = JSON.stringify(data[7][0].summary.steps);
        const totalStepsSoFar = JSON.stringify(data[1][0].summary.steps);

        //console.log("here's where you're putting our INSERT code");

        Profile.find({ empID: empID, todaysDate: today }).then(profile => {
          if (profile) {
            //console.log("someone's here");
            profile.empID = empID;
            profile.todaysDate = today;
            profile.firstName = firstName;
            profile.lastName = lastName;
            profile.dateOfBirth = dateOfBirth;
            profile.gender = gender;
            profile.bodyStartWeight = startWeight;
            profile.bodyTargetWeight = targetWeight;
            profile.calorieGoal = calories_goal;
            profile.caloriesConsumed = caloriesIn;
            profile.caloriesBurned = calories_burned;
            profile.waterConsumpution = water;
            profile.BMR = BMR;
            profile.totalHoursSlept = sleep;
            profile.REM = rem_sleep;
            profile.RHR = rhr;
            profile.totalStepsYesterday = totalStepsYesterday;
            profile.totalStepsSoFar = totalStepsSoFar;
            return Profile.save()
              .then(result => {
                console.log("updated row");
              })
              .catch(err => {
                const error = new Error(err);
                error.httpStatusCode = 500;
                return next(error);
              });
          } else {
            const profile = new Profile({
              empID: empID,
              todaysDate: today,
              firstName: firstName,
              lastName: lastName,
              dateOfBirth: dateOfBirth,
              gender: gender,
              bodyStartWeight: startWeight,
              bodyTargetWeight: targetWeight,
              calorieGoal: calories_goal,
              caloriesConsumed: caloriesIn,
              caloriesBurned: calories_burned,
              waterConsumpution: water,
              BMR: BMR,
              totalHoursSlept: sleep,
              REM: rem_sleep,
              RHR: rhr,
              totalStepsYesterday: totalStepsYesterday,
              totalStepsSoFar: totalStepsSoFar
            });
            profile
              .save()
              .then(result => {
                console.log("got it done");
                res.redirect("/success");
              })
              .catch(err => {
                const error = new Error(err);
                error.httpStatusCode = 500;
                return next(error);
              });
          }
        });
      }) // end of update or insert
      .catch(err => {
        const error = new Error(err);
        error.httpStatusCode = 500;
        return next(error);
      });
  });
};

exports.getSuccess = (req, res, next) => {
  console.log("hello");
  res.status(200).render("authorize/success", {
    pageTitle: "Success",
    path: "/success"
  });
};

Open in new window


What you're looking at is good to except for the one piece of functionality that you see on line #105.

I'm trying to differentiate between adding a row or updating an already existing row.

I'm new to Node, so I'm trying to mimic the Udemy tutorial I'm going through, but I'm missing something because I keep getting an error that says, "UnhandledPromiseRejectionWarning: TypeError: Profile.save is not a function."

For the sake of brevity, that's going to be right here:

Profile.find({ empID: empID, todaysDate: today }).then(profile => {
          if (profile) {
            //console.log("someone's here");
            profile.empID = empID;
            profile.todaysDate = today;
            profile.firstName = firstName;
            profile.lastName = lastName;
            profile.dateOfBirth = dateOfBirth;
            profile.gender = gender;
            profile.bodyStartWeight = startWeight;
            profile.bodyTargetWeight = targetWeight;
            profile.calorieGoal = calories_goal;
            profile.caloriesConsumed = caloriesIn;
            profile.caloriesBurned = calories_burned;
            profile.waterConsumpution = water;
            profile.BMR = BMR;
            profile.totalHoursSlept = sleep;
            profile.REM = rem_sleep;
            profile.RHR = rhr;
            profile.totalStepsYesterday = totalStepsYesterday;
            profile.totalStepsSoFar = totalStepsSoFar;
            return Profile.save()
              .then(result => {
                console.log("updated row");
              })

Open in new window


That's lines 108 - 131.

What am I doing wrong?
Avatar of leakim971
leakim971
Flag of Guadeloupe image

profile.save()

The << P >> should be lowercase
Avatar of Bruce Gust

ASKER

I get the same error...
yes  this is not a Profile but the json data itself
do what you did line 138 to 157 :

Profile.find({ empID: empID, todaysDate: today }).then(profile => {
    if (profile) {

        const new_profile = new Profile({
            empID: profile.empID,
            todaysDate: profile.todaysDate,
            firstName: profile.firstName,
            lastName: profile.lastName,
            dateOfBirth: profile.dateOfBirth,
            gender: profile.gender,
            bodyStartWeight: profile.startWeight,
            bodyTargetWeight:profile.targetWeight,
            calorieGoal: profile.calories_goal,
            caloriesConsumed: profile.caloriesIn,
            caloriesBurned: profile.calories_burned,
            waterConsumpution: profile.water,
            BMR: profile.BMR,
            totalHoursSlept: profile.sleep,
            REM: profile.rem_sleep,
            RHR: profile.rhr,
            totalStepsYesterday: profile.totalStepsYesterday,
            totalStepsSoFar: profile.totalStepsSoFar
        });
        new_profile.save()

Open in new window

Leak, this is going to work! But, I wanted to run something by you because it feels kind of clunky.

At first, I couldn't get it to work. Then I did a console log of "person" like what you see below.

 Profile.find({ empID: empID, todaysDate: today }).then(person => {
          if (person) {
            [b]console.log(person[0].empID);[/b]
            const profile = new Profile({
              empID: person.empID,
              todaysDate: person.today,
              firstName: person.firstName,
              lastName: person.lastName,
              dateOfBirth: person.dateOfBirth,
              gender: person.gender,
              bodyStartWeight: person.startWeight,
              bodyTargetWeight: person.targetWeight,
              calorieGoal: person.calories_goal,
              caloriesConsumed: person.caloriesIn,
              caloriesBurned: person.calories_burned,
              waterConsumpution: person.water,
              BMR: person.BMR,
              totalHoursSlept: person.sleep,
              REM: person.rem_sleep,
              RHR: person.rhr,
              totalStepsYesterday: person.totalStepsYesterday,
              totalStepsSoFar: person.totalStepsSoFar
            });
            profile
              .save()
              .then(result => {
                console.log("got it done");
                res.redirect("/success");
              })
              .catch(err => {
                const error = new Error(err);
                error.httpStatusCode = 500;
                return next(error);
              });
          }

Open in new window


You see the line I've got in bold? Keep that in mind.

Initially I couldn't get it to work and then I console-logged out "person" and this is what I got:

[ { _id: 5dcd9411a80284295ce8be11,
    empID: 7747,
    todaysDate: '2019-11-14',
    firstName: 'Bruce',
    lastName: 'Gust',
    dateOfBirth: '1963-08-26',
    gender: 'MALE',
    bodyStartWeight: 180,
    bodyTargetWeight: 170,
    calorieGoal: 2692,
    caloriesConsumed: 0,
    caloriesBurned: 481,
    BMR: 809,
    totalHoursSlept: 5.3,
    REM: 60,
    RHR: 53,
    totalStepsYesterday: 17127,
    totalStepsSoFar: 4990,
    __v: 0 } ]

Open in new window


It wasn't until I did person[0].empID etc that I could retrieve any of the values.

That feels kind of clunky. Am I doing something wrong?
No, it's normal behavior, find return array of objects
You may want to use findOne which return one object
Actually, Leak...

It's adding another record. IT's not updating what's already there. So I'm not getting any errors but I need to update what's there and not add another record when there's a match between the empID and the date.

Where am I blowing it?
Where am I blowing it?

The _id is not set

Check this too :

Profile.findOne({ empID: empID, todaysDate: today }).then(profile => {
    if(profile) {
        const new_profile = {
            todaysDate: profile.todaysDate,
            firstName: profile.firstName,
            lastName: profile.lastName,
            dateOfBirth: profile.dateOfBirth,
            gender: profile.gender,
            bodyStartWeight: profile.startWeight,
            bodyTargetWeight: profile.targetWeight,
            calorieGoal: profile.calories_goal,
            caloriesConsumed: profile.caloriesIn,
            caloriesBurned: profile.calories_burned,
            waterConsumpution: profile.water,
            BMR: profile.BMR,
            totalHoursSlept: profile.sleep,
            REM: profile.rem_sleep,
            RHR: profile.rhr,
            totalStepsYesterday: profile.totalStepsYesterday,
            totalStepsSoFar: profile.totalStepsSoFar
        };
        Profile.replaceOne({ _id : profile._id }, new_profile);
    }
});

Open in new window

Leak, we're getting closer but it's still not working. And the thing is, it's inconsistent.

First thing I noticed is that I lost some data. I shot in the dark and I was able to solve that dilemma by doing this:

const new_profile = {
              todaysDate: today,
              firstName: firstName,
              lastName: lastName,
              dateOfBirth: dateOfBirth,
              gender: gender,
              bodyStartWeight: startWeight,
              bodyTargetWeight: targetWeight,
              calorieGoal: calories_goal,
              caloriesConsumed: caloriesIn,
              caloriesBurned: calories_burned,
              waterConsumpution: water,
              BMR: BMR,
              totalHoursSlept: sleep,
              REM: rem_sleep,
              RHR: rhr,
              totalStepsYesterday: totalStepsYesterday,
              totalStepsSoFar: totalStepsSoFar
            };

            return Profile.replaceOne({ _id: profile._id }, new_profile)

Open in new window


But after that got ironed out, I noticed that it would still add another row even when it was supposed to be updating what was already there.

Here's the whole thing:

require("dotenv").config();
const { validationResult } = require("express-validator/check");
const mongoose = require("mongoose");
const Profile = require("../models/profile");
const ClientId = process.env.CLIENTID;
const Secret = process.env.SECRET;
const Callback = process.env.CALLBACK;

//this is the empID you're getting from AHA
const empID = 7747;

//get today's date
let date_ob = new Date();

// current date
// adjust 0 before single digit date
let date = ("0" + date_ob.getDate()).slice(-2);

// current month
let month = ("0" + (date_ob.getMonth() + 1)).slice(-2);

// current year
let year = date_ob.getFullYear();

// prints date in YYYY-MM-DD format
let today = year + "-" + month + "-" + date;

const FitbitApiClient = require("fitbit-node");
const client = new FitbitApiClient({
  clientId: ClientId, //client_id
  clientSecret: Secret, //client secret
  apiVersion: "1.2" // 1.2 is the default
});

exports.getCallback = (req, res, next) => {
  const yesterday_raw = new Date(new Date().setDate(new Date().getDate() - 1));
  const yesterday = yesterday_raw.toISOString().slice(0, 10);

  client.getAccessToken(req.query.code, Callback).then(result => {
    var requests = [
      client.get("/profile.json", result.access_token), //0
      client.get("/activities/date/today.json", result.access_token), //1
      //client.get("/sleep/date/" + yesterday + ".json", result.access_token), //2
      client.get("/sleep/date/today.json", result.access_token), //2
      //client.get("/sleep/date/2019-11-05.json", result.access_token), //2
      client.get(
        "/foods/log/caloriesIn/date/today/1d.json",
        result.access_token
      ), //dailly intake of calories 3
      client.get("/foods/log/water/date/today.json", result.access_token), // 4 this works!
      client.get("/activities/heart/date/today/1d.json", result.access_token), //5
      client.get("/body/log/weight/goal.json", result.access_token, undefined, {
        "Accept-Language": "en_US"
      }), //6
      client.get("/activities/date/" + yesterday + ".json", result.access_token) //7
    ];
    Promise.all(requests)
      .then(data => {
        //profile info
        const firstName = data[0][0].user.firstName; //0
        const lastName = data[0][0].user.lastName; //0
        const dateOfBirth = data[0][0].user.dateOfBirth; //0
        const gender = data[0][0].user.gender; //0

        //calorie goals - to be burned including BMR
        const calories_goal = JSON.stringify(data[1][0]["goals"].calories); //1 calorie goal
        const massive_total = JSON.stringify(data[1][0].summary.calories.total); //1 big calorie total
        const BMR = JSON.stringify(data[1][0].summary.calories.bmr); //1 - BMR
        const calories_burned = massive_total - BMR;

        //sleep
        const slumber = JSON.stringify(
          data[2][0].summary.totalMinutesAsleep / 60
        ); //2 total sleep hours
        const sleep = JSON.stringify(Math.round(slumber * 10) / 10);

        const rem_sleep = data[2][0]["sleep"].length
          ? data[2][0]["summary"].stages.rem
          : 0; //minutes in deep REM sleep

        //nutrition
        const eating = JSON.stringify(
          data[3][0]["foods-log-caloriesIn"][0].value
        ); //3
        const caloriesIn = eating.replace(/\"/g, "");

        //water
        const water = JSON.stringify(data[4][0].summary.water);

        //heart rate
        const rhr = JSON.stringify(
          data[5][0]["activities-heart"][0].value.restingHeartRate
        );

        //body weight goal
        //res.setHeader('Accept-Language', 'en_US')
        const startWeight = JSON.stringify(data[6][0].goal.startWeight);
        const targetWeight = JSON.stringify(data[6][0].goal.weight);
        //res.send(targetWeight);

        //steps
        const totalStepsYesterday = JSON.stringify(data[7][0].summary.steps);
        const totalStepsSoFar = JSON.stringify(data[1][0].summary.steps);

        //console.log("here's where you're putting our INSERT code");

        Profile.findOne({ empID: empID, todaysDate: today }).then(profile => {
          if (profile) {
            // console.log(person[0][0].empID);

            const new_profile = {
              todaysDate: today,
              firstName: firstName,
              lastName: lastName,
              dateOfBirth: dateOfBirth,
              gender: gender,
              bodyStartWeight: startWeight,
              bodyTargetWeight: targetWeight,
              calorieGoal: calories_goal,
              caloriesConsumed: caloriesIn,
              caloriesBurned: calories_burned,
              waterConsumpution: water,
              BMR: BMR,
              totalHoursSlept: sleep,
              REM: rem_sleep,
              RHR: rhr,
              totalStepsYesterday: totalStepsYesterday,
              totalStepsSoFar: totalStepsSoFar
            };

            return Profile.replaceOne({ _id: profile._id }, new_profile)
              .then(result => {
                console.log("got it done");
                res.redirect("/success");
              })
              .catch(err => {
                const error = new Error(err);
                error.httpStatusCode = 500;
                return next(error);
              });
          } else {
            const profile = new Profile({
              empID: empID,
              todaysDate: today,
              firstName: firstName,
              lastName: lastName,
              dateOfBirth: dateOfBirth,
              gender: gender,
              bodyStartWeight: startWeight,
              bodyTargetWeight: targetWeight,
              calorieGoal: calories_goal,
              caloriesConsumed: caloriesIn,
              caloriesBurned: calories_burned,
              waterConsumpution: water,
              BMR: BMR,
              totalHoursSlept: sleep,
              REM: rem_sleep,
              RHR: rhr,
              totalStepsYesterday: totalStepsYesterday,
              totalStepsSoFar: totalStepsSoFar
            });
            profile
              .save()
              .then(result => {
                console.log("got it done");
                res.redirect("/success");
              })
              .catch(err => {
                const error = new Error(err);
                error.httpStatusCode = 500;
                return next(error);
              });
          }
        });
      }) // end of update or insert
      .catch(err => {
        const error = new Error(err);
        error.httpStatusCode = 500;
        return next(error);
      });
  });
};

exports.getSuccess = (req, res, next) => {
  console.log("hello");
  res.status(200).render("authorize/success", {
    pageTitle: "Success",
    path: "/success"
  });
};

Open in new window

OK!

I've made some progress, but I'm still not there...

This works, as far as entering a new row. Where it fails is in the context of updating that same row. No errors. I get redirected and I get my console message. But you'll see how I've hardcoded "8000" for the caloriesBurned value and that never gets changed.

Leak, I tried your approach and it wiped out everything save the id. Wanted to make sure you knew I was trying your suggestions...!

Here's what I've got. Why doesn't this script update what's in the database?

 Profile.findOne({ empID: empID, todaysDate: today })
          .then(person => {
            if (person) {
              // console.log(person[0][0].empID);
              console.log(calories_burned);
              _id: person._id;
              empID: empID;
              firstName: firstName;
              lastName: lastName;
              dateOfBirth: dateOfBirth;
              gender: gender;
              bodyStartWeight: startWeight;
              bodyTargetWeight: targetWeight;
              calorieGoal: calories_goal;
              caloriesConsumed: caloriesIn;
              caloriesBurned: 8000;
              waterConsumpution: water;
              BMR: BMR;
              totalHoursSlept: sleep;
              REM: rem_sleep;
              RHR: rhr;
              totalStepsYesterday: totalStepsYesterday;
              totalStepsSoFar: totalStepsSoFar;
              person
                .save()
                .then(result => {
                  console.log("updated");
                  res.redirect("/update");
                })
                .catch(err => {
                  const error = new Error(err);
                  return next(error);
                });
            } else {
              const profile = new Profile({
                empID: empID,
                todaysDate: today,
                firstName: firstName,
                lastName: lastName,
                dateOfBirth: dateOfBirth,
                gender: gender,
                bodyStartWeight: startWeight,
                bodyTargetWeight: targetWeight,
                calorieGoal: calories_goal,
                caloriesConsumed: caloriesIn,
                caloriesBurned: calories_burned,
                waterConsumpution: water,
                BMR: BMR,
                totalHoursSlept: sleep,
                REM: rem_sleep,
                RHR: rhr,
                totalStepsYesterday: totalStepsYesterday,
                totalStepsSoFar: totalStepsSoFar
              });
              profile
                .save()
                .then(result => {
                  console.log("got it done");
                  res.redirect("/success");
                })
                .catch(err => {
                  const error = new Error(err);
                  error.httpStatusCode = 500;
                  return next(error);
                });
            }
          })
          .catch(err => {
            const error = new Error(err);
            return next(error);
          });

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of leakim971
leakim971
Flag of Guadeloupe image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
We got it figured out, Leak! Thanks!