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

Bruce Gust
Bruce Gust used Ask the Experts™
on
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?
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
leakim971Multitechnician
Top Expert 2014

Commented:
profile.save()

The << P >> should be lowercase
Bruce GustPHP Developer

Author

Commented:
I get the same error...
leakim971Multitechnician
Top Expert 2014

Commented:
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

Success in ‘20 With a Profitable Pricing Strategy

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Bruce GustPHP Developer

Author

Commented:
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?
leakim971Multitechnician
Top Expert 2014

Commented:
No, it's normal behavior, find return array of objects
You may want to use findOne which return one object
Bruce GustPHP Developer

Author

Commented:
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?
leakim971Multitechnician
Top Expert 2014

Commented:
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

Bruce GustPHP Developer

Author

Commented:
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

Bruce GustPHP Developer

Author

Commented:
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

Multitechnician
Top Expert 2014
Commented:
I can't find a reason Profile.replaceOne add a new row
and why suddently adding "return " front of it hen you don't do it for save?
Are you sure the new row come from that code?
Bruce GustPHP Developer

Author

Commented:
We got it figured out, Leak! Thanks!

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial