0

So I have a Mongoose Model called Profile:

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const ProfileSchema = new Schema({
  user: {
    type: mongoose.Schema.ObjectId,
    ref: "user",
  },
  company: {
    type: String,
  },
  website: {
    type: String,
  },
  location: {
    type: String,
  },
  status: {
    type: String,
    required: true,
  },
  skills: {
    type: [String],
    required: true,
  },
  bio: {
    type: String,
  },
  githubusername: {
    type: String,
  },
  experience: [{
    title: {
      type: String,
      required: true,
    },
    company: {
      type: String,
      required: true,
    },
    location: {
      type: String,
    },
    from: {
      type: Date,
      required: true,
    },
    to: {
      type: Date,
    },
    current: {
      type: Boolean,
      default: false,
    },
    description: {
      type: String,
    },
  }, ],
  education: [{
    school: {
      type: String,
      required: true,
    },
    degree: {
      type: String,
      required: true,
    },
    fieldofstudy: {
      type: String,
      required: true,
    },
    from: {
      type: Date,
      required: true,
    },
    to: {
      type: Date,
    },
    current: {
      type: Boolean,
      default: false,
    },
    description: {
      type: String,
    },
  }, ],
  social: {
    youtube: {
      type: String,
    },
    twitter: {
      type: String,
    },
    facebook: {
      type: String,
    },
    linkedin: {
      type: String,
    },
    instagram: {
      type: String,
    },
  },
  date: {
    type: Date,
    default: Date.now,
  },
});

module.exports = Profile = mongoose.model("profile", ProfileSchema);

As you can see I have a bunch of nested subdocuments and I want to be able to update them. In particular I want to be able to able to update the experience with a PUT endpoint.

Here is the endpoint to add an experience:

router.put(
  "/experience", [
    auth, [
      check("title", "Title is required").not().isEmpty(),
      check("company", "Company is required").not().isEmpty(),
      check("from", "From date is required and needs to be from the past")
      .not()
      .isEmpty()
      .custom((value, {
        req
      }) => (req.body.to ? value < req.body.to : true)),
    ],
  ],
  async(req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({
        errors: errors.array()
      });
    }

    const {
      title,
      company,
      location,
      from,
      to,
      current,
      description,
    } = req.body;

    const newExp = {
      title,
      company,
      location,
      from,
      to,
      current,
      description,
    };

    try {
      const profile = await Profile.findOne({
        user: req.user.id
      });

      profile.experience.unshift(newExp);

      await profile.save();

      res.json(profile);
    } catch (err) {
      console.error(err.message);
      res.status(500).send("Server Error");
    }
  }
);

And this works I am able to add an experience to that array. But When I try and Update it does not work here is what I have tried:

router.put("/experience/:exp_id", auth, async(req, res) => {
  try {
    const profile = await Profile.experience.findByIdAndUpdate(
      req.params._id, {
        $set: req.body,
      }, {
        new: true
      }
    );
    res.json(profile);
  } catch (error) {
    console.error(error);
    return res.status(500).json({
      msg: "Server error"
    });
  }
});

I get this error TypeError: Cannot read property 'findByIdAndUpdate' of undefined what am I doing wrong?

Here is a some Profile data I have when I create a Profile

{
  "social": {
    "youtube": "https://youtube.com/user/mojara2009",
    "twitter": null,
    "instagram": null,
    "linkedin": "https://linkedin.com/in/amen-ra",
    "facebook": null
  },
  "skills": [
    " HTML",
    " CSS",
    " JAVASCRIPT",
    " REACT",
    " REDUX",
    " JEST"
  ],
  "_id": "5eb1a19b83001bdb87e26492",
  "user": {
    "_id": "5eb10fecc3de3526caba5e50",
    "name": "Amen Ra",
    "avatar": "//www.gravatar.com/avatar/ee452fcb90a3913ca75ed4b4f06c4de6?s=200&r=pg&d=mm"
  },
  "__v": 19,
  "bio": "I am a Senior Full Stack Developer for Web App Company",
  "company": "Web App Company",
  "githubusername": "mojaray2k",
  "location": "Aventura, Fl",
  "status": "Developer",
  "website": "https://imaginationeverywhere.info",
  "date": "2020-05-05T22:33:41.596Z",
  "education": [{
      "current": false,
      "_id": "5eb2eccd659559371b2162f4",
      "school": "Bethune-Cookman University",
      "degree": "Bachelor of Arts",
      "fieldofstudy": "Mass Communication",
      "from": "1994-08-04T00:00:00.000Z",
      "to": "1999-04-26T00:00:00.000Z",
      "description": "Attended Bethune Cookman College in Daytona Beach, Fl"
    },
    {
      "current": false,
      "_id": "5eb2ecc2659559371b2162f3",
      "school": "Manual High School",
      "degree": "Diploma",
      "fieldofstudy": "NA",
      "from": "1990-09-01T00:00:00.000Z",
      "to": "1994-06-01T00:00:00.000Z",
      "description": "Attended High School my sophomore through senior year"
    },
    {
      "current": false,
      "_id": "5eb2ecb5659559371b2162f2",
      "school": "John F. Kennedy High School",
      "degree": "NA",
      "fieldofstudy": "NA",
      "from": "1989-09-01T00:00:00.000Z",
      "to": "1990-06-01T00:00:00.000Z",
      "description": "Attended High School my sophomore through senior year"
    },
    {
      "current": false,
      "_id": "5eb2ea28659559371b2162eb",
      "school": "Kunsmiller",
      "degree": "NA",
      "fieldofstudy": "Middle School",
      "from": "1988-02-01T05:00:00.000Z",
      "to": "1989-06-01T04:00:00.000Z",
      "description": "Attended Middle School There"
    }
  ],
  "experience": [{
      "current": false,
      "_id": "5eb356f74cc1ad499167567d",
      "title": "Senior Full Stack Engineer",
      "company": "Concept Solutions",
      "location": "Aventura, Fl",
      "from": "2016-01-03T00:00:00.000Z",
      "to": "2018-02-28T00:00:00.000Z",
      "description": "Worked as Full Stack Developer"
    },
    {
      "current": false,
      "_id": "5eb2de8fccd73b25fd1b2b39",
      "title": "Senior Full Stack Engineer",
      "company": "Jehovah Jireh, Inc",
      "location": "Aventura, Fl",
      "from": "2018-07-01T04:00:00.000Z",
      "to": "2019-07-01T04:00:00.000Z",
      "description": "Worked as Full Stack Developer"
    },
    {
      "current": true,
      "_id": "5eb203af1e004371b3284883",
      "title": "Senior Full Stack Engineer",
      "company": "Web App Company",
      "location": "Aventura, Fl",
      "from": "2019-07-01T04:00:00.000Z",
      "description": "Worked as Full Stack Developer"
    }
  ]
}

1
  • @Fayad That does not work Commented May 7, 2020 at 1:40

3 Answers 3

1

It is not possible to access a mongoose model schema as a Profile object. Instead if you want to update a specific part of the model, in this case experience, you can do as follows:

try {
    const await profile = Profile.findOneAndUpdate(
        { experience: { $elemMatch: { _id: req.params.exp_id } } },
        { $set: { 'experience.$': req.body } },
        { new: true }
    );
    res.json(profile);
} catch (error) {
    console.error(error);
    return res.status(500).json({ msg: 'Server error' });
}

Also I believe it be req.params.exp_id instead of req.params._id.

Sign up to request clarification or add additional context in comments.

8 Comments

That does not work. This is the error I am getting Cannot read property 'findByIdAndUpdate' of undefined
Do you have a reference to the model, something like var Profile = require('PATH_TO_PERSON_MODEL')
This is what I have imported const Profile = require("../../models/Profile");
I have edited my answer incase you have copied it, since I have put Person instead of Profile by mistake, let me know if that was the case.
What do you put in the callback? Because I am getting null.
|
0

Thats a normal response for mongoose, Because Profile is a Collection Model Schema, not an Profile object. Also if you want to update an specific element on the array, You need to add query to help mongo to find which data will only update on the array.

Here's the alternate query for updating collection data on mongo.

    router.put("/:profile_id/experience/:exp_id", auth, async(req, res) => {
     const {profile_id = '', exp_id = ''} = req.params
      try {
        const profile = await Profile.findOne(
          {
             _id: mongoose.mongo.ObjectId(profile_id)
          }
        );
        if (!profile) {
           throw new Error('No profile found.')
        }
        const index = profile.experience.findIndex((exp) => exp._id === mongoose.mongo.ObjectId(exp_id))
        if (index === -1) {
           throw new Error('No experience data found.')
        }
        const {_id, ...experience} = req.body
        profile.experience[index] = experience
        profile.save
        res.json(profile);
      } catch (error) {
        console.error(error);
        return res.status(500).json({
          msg: "Server error"
        });
      }
    });

20 Comments

I get this error TypeError: Cannot read property 'experience' of null
I think thats mean that the exp id is not existing on the profile collection
This is what the experience array looks like: experience[ { "current": false, "_id": "5eb356f74cc1ad499167567d", "title": "Senior Full Stack Engineer", "company": "Concept Innovations", "location": "Aventura, Fl", "from": "2016-01-03T00:00:00.000Z", "to": "2018-02-28T00:00:00.000Z", "description": "Worked as Full Stack Developer" }]
ohh. i think you need to convert the _id or exp_id inside of the "req.body" from string to ObjectId of mongoose.
Yeah the root object also has an _id along with experience which each one has it's own _id
|
0

just use:

const profile = await Profile.findOneAndUpdate

instead of const profile = await Profile.experience.findByIdAndUpdate

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.