Reputation: 797
here is the UserSchema:
var UserSchema = new Schema({
username: { type: String, required: true, index:{unique: true} },
firstName: { type: String, required: true },
lastName: { type: String, required: true },
email: { type: String, required: true, index:{unique: true} },
password: { type: String, required: true, select: false }
});
Here is the http PUT request:
// update user information
api.put('/users/:username', function(req, res) {
User.findOne({username: req.params.username}, function(err, user) {
if (err){
res.send(err);
return;
}
if (!user){
res.status(404).send({
success: false,
message: "user not found"
});
} else {
user.username = req.body.username;
user.email = req.body.email;
user.password = req.body.password;
user.firstName = req.body.firstName;
user.lastName = req.body.lastName;
user.save(function(err) {
if (err){
res.send(err);
return;
}
res.json({
success: true,
message: "user information updated."
});
});
}
});
});
The question is, if the user only want to update limited fields, for example, only update username, then the above code does not work, the error looks like this:
{
"message": "User validation failed",
"name": "ValidationError",
"errors": {
"lastName": {
"properties": {
"type": "required",
"message": "Path `{PATH}` is required.",
"path": "lastName"
},
"message": "Path `lastName` is required.",
"name": "ValidatorError",
"kind": "required",
"path": "lastName"
},
"firstName": {
"properties": {
"type": "required",
"message": "Path `{PATH}` is required.",
"path": "firstName"
},
.........
so how can I implemement to allow user updates some but not all fields?
Any comments and suggestions are appreciated!
Upvotes: 4
Views: 17233
Reputation: 4590
I ended up using this solution:
const dot = require('dot-object'); // this package works like magic
const updateData = { some: true, fields: true };
User.updateOne(
{ _id: req.user._id },
{ $set: dot.dot(updateData) },
(err, results) => {
if (err) res.json({ err: true });
else res.json({ success: true });
}
);
I found this idea here: https://github.com/Automattic/mongoose/issues/5285#issuecomment-439378282
Upvotes: 5
Reputation: 41
This is a good compromise:
Specify the fields that the user can update
let fieldToUpdate = {
name: req.body.name,
email: req.body.email,
};
Then delete all the keys that contains falsy value
for (const [key, value] of Object.entries(fieldToUpdate)) {
if (!value) {
delete fieldToUpdate[key];
}
}
Then Update the value using the $set operator
const user = await User.findByIdAndUpdate(
req.user.id,
{ $set: { ...fieldToUpdate } },
{
runValidators: true,
new: true,
}
);
Upvotes: 4
Reputation: 104
From what I understand is that you want to be able to update any amount of fields. The code below is from a past project.
Model
const ingredientSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type:String, required: true },
quantity: { type: Number, default: 0}
});
HTTP PUT
router.put('/:ingredientId', (req, res, next) => {
// extracting ingredient id from url parameters
const id = req.params.ingredientId;
//creating a map from the passed array
const updateOps = {};
for(const ops of req.body){
updateOps[ops.propName] = ops.value;
}
//updating the found ingredient with the new map
Ingredient.update({_id: id}, { $set: updateOps})
.exec()
.then(result =>{
console.log(result);
//returning successful operation information
res.status(200).json(result);
})
//catching any errors that might have occured from above operation
.catch(err => {
console.log(err);
//returning server error
res.status(500).json({
error: err
});
});
});
PUT Request (json)
[
{"propName": "name", "value": "Some other name"},
{"propName": "quantity", "value": "15"},
]
or if you one want to update one field
[
{"propName": "name", "value": "Some other name"}
]
basically you have an array of these property/field names and their new values. you can update just one or all of them this way if you would like. Or none of them I believe.
Hopefully, this helps! if you have any questions just ask!
Upvotes: 2
Reputation: 1073
Using findOneAndUpdate with the operator $set in the update object:
User.findOneAndUpdate({username: req.params.username}, { $set: req.body }, { new: true }, callback);
$set
will allow you to modify only the supplied fields in the req.body
object.
Upvotes: 9
Reputation: 10899
You can use the 'findOneAndUpdate' method.
User.findOneAndUpdate({username: req.params.username}, {username: req.body.username}, function(err, user) {
//...
});
Upvotes: 2