ipenguin67
ipenguin67

Reputation: 1649

How can I intelligently update a Mongoose document based on variable request data?

For my Edit user route, I will need to handle a number of different possible circumstances. A user could update their profile and only change their email address or password, but they might update a whole range of other profile information at once too.

The advantage of findOneAndUpdate is that you can pass the update object and it will only change those fields from the request that are different than the saved data. This is great! One HUGE problem -- this query bypasses validators and middleware for some reason (even with runValidators=true, it bypasses pre-save hooks, meaning password updates bypass being encrypted).

So the solution I keep seeing everywhere is to do a findOne or findById, update fields manually, and then run user.save().

However, with a fairly complicated user record, that means my route would look something like this and would be very hard to maintain:

exports.editUser = async function(req, res, next) {
  try {
    const id = req.params.id;
    let user = await db.User.findById(id);
    user.email = req.body.email;
    user.fullName = req.body.fullName;
    user.password = req.body.password;
    user.otherField = req.body.otherField;
    user.otherField = req.body.otherField;
    user.otherField = req.body.otherField;
    user.otherField = req.body.otherField;
    user.otherField = req.body.otherField;
    user.otherField = req.body.otherField;
    user.otherField = req.body.otherField;
    user.otherField = req.body.otherField;
    user.otherField = req.body.otherField;
    user.otherField = req.body.otherField;
    user.otherField = req.body.otherField;
    let updatedUser = await user.save();
    return res.status('200').json(user); 
  }

Is there any way to mimic the behavior of passing the updates object to Mongoose where I can just give it req.body and let it only update the fields that are different?

Upvotes: 0

Views: 26

Answers (1)

blackening
blackening

Reputation: 953

https://lodash.com/docs/4.17.11#merge

_.merge(user, req.body)

This will merge **EVERYTHING **. Use only if you don't care about security.

To limit to certain fields without going crazy:

const { f1, f2, f3 } = req.body;
_.merge(user, { f1, f2, f3}) 

Or refer to this: https://lodash.com/docs/4.17.11#pick
Slightly non-obvious feature in lodash.

_.merge(user, _.pick(req.body, ['f1', 'f2', 'f3']))

Upvotes: 1

Related Questions