Eccentric291
Eccentric291

Reputation: 107

How can I update some fields of an embedded object using mongoose's findOneAndUpdate method and not lose the other fields?

 router.put('/experience/update/:exp_id',
    auth,
    async (req, res) => {

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

        const newExp = {};
        newExp._id = req.params.exp_id;

        if (title) newExp.title = title;
        if (company) newExp.company = company;
        if (location) newExp.location = location;
        if (from) newExp.from = from;
        if (to) newExp.to = to;
        if (current) newExp.current = current;
        if (description) newExp.description = description;

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

            if (profile) {
                //UPDATE Experience
                profile = await Profile.findOneAndUpdate(
                    { user: req.user.id });
                const updateIndex = profile.experience.map(exp => exp._id).indexOf(req.params.exp_id);

                profile.experience[updateIndex] = newExp;
                    console.log('Experience updated!')
            }
            await profile.save();
            res.json(profile);

        } catch (error) {
            console.log(error.message);
            res.status(500).send('Internal Server Error');
        }


    }
)

I am using the findOneAndUpdate method to update the experience field inside a profile mongoose model. After accesssing the endpoint, I put the updated details, for eg. company and location. But I lose all the other fields. So how can I update only select fields while others remain unchanged ?

Below is the profile schema:

    const mongoose = require('mongoose');

const ProfileSchema = new mongoose.Schema({
    user: {
        type: mongoose.Schema.Types.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,
                required: true
            },
            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);

Upvotes: 2

Views: 1805

Answers (1)

wak786
wak786

Reputation: 1615

There are some problems in your code.

  1. You are passing only one argument to findOneAndUpdate. Ideally the syntax is findOneAndUpdate(filter, update). So basically you need to pass update query as 2nd argument.
profile = await Profile.findOneAndUpdate(
                    { user: req.user.id });
  1. In below code you are modifying the profile object and saving it. Which is not required. And this is also the reason why you are losing fields.
 const updateIndex = profile.experience.map(exp => exp._id).indexOf(req.params.exp_id);

                profile.experience[updateIndex] = newExp;
                    console.log('Experience updated!')
            }
            await profile.save();

Solution-

We need to figure out the update part of findOneAndUpdate(filter, update).

Here is the update query -

db.collection.update({
  "user": "5f96dc85ac5ae03160a024a8",
  "experience._id": "5f9826c3a3fa002ce0f11853"
},
{
  "$set": {
    "experience.$": {
      "current": false,
      "_id": "5f9826c3a3fa002ce0f11853",
      "title": "Senior developer",
      "company": "Morgan Stanley",
      "location": "Pune",
      "from": "2017-04-30T18:30:00.000Z",
      "to": "2020-07-08T18:30:00.000Z",
      "description": "testing"
    }
  }
})

Try it here

Trying Mongoose way :

const filter = { user: req.user.id, "experience._id": req.params.exp_id }
const update = { $set: { "experience.$": newExp } }
profile = await Profile.findOneAndUpdate(filter,update);

Upvotes: 3

Related Questions