Reputation: 1320
I have a simple application that communicates with an API build with NodeJS+Express+MongoDB (mongoose). My question is referred to the API side.
I use this schema to store user configuration in MongoDB:
{
user: Number,
name: String,
lists: {
invoices: {
year: Number,
orderCol: String,
order: Number
}
}
}
}
There is only one document per user, that stores values used by my frontend app to show a list of invoices sorted and filtered by year.
I need to update the document, but it has to update only one property each time. For example, with a call to API I want to be able to change user.lists.invoices.year
to 2017, without changing order
&orderCol
.
I'm sending three values to the API: type of list (invoices
), property to change (year
) and value to set (2017
).
// PUT request with this payload
{
list: 'invoices',
property: 'year',
value: 2017
}
I'm using user
field to query.
router.put('/lists/:usr', (req, res, next) => {
var listData = req.body; // listData.list, listData.property, listData.year
var usr = req.params.usr;
Config.findOneAndUpdate(
{ user: usr },
{ $set: { ??? } },
{ new: true, upsert: true },
(err, config) => {
if (err) return next(err);
res.json({ data: config });
}
)
})
Note for possible dupplicates: my searches in Google and SO always lead me to $
operator, but I don't know if it's the solution for this, and in any case I don't know how to use it in this case.
Maybe it's just I'm not designing the right Schema, in which case I'd aprecciate any advice.
Upvotes: 1
Views: 2070
Reputation: 791
I'm not so sure about the whole API structure but I think we can solve this specific problem by the following code:
Config.findOne({ user: usr }, (err, config) => {
if (err) return next(err);
// Be careful if config.lists[list] or config.lists[list][property] can be undefined
config.lists[list][property] = value;
// this might be needed
// config.markModified('lists.' + list + '.' + property);
config.save(err => {
if (err) return next(err);
res.json({ data: config });
});
});
We can always find the document(s) first, apply some modifications directly before saving it again into the database instead of using the update functions.
Also, this kind of update API seems a bit unusual and I won't be able to tell if it works well for you or not. Regardless, I would suggest adding a validation middleware. Something as simple as this may help:
function validator(req, res, next) {
const fields = ['list', 'property', 'value'];
if (!fields.every(field => req.body[field] !== undefined)) {
return res.status(400).json({ error: 1, msg: fields.join(', ') + ' are required' });
}
if (['invoices', 'interests', 'etc'].indexOf(req.body.list) === -1) {
return res.status(400).json({ error: 1, msg: 'list is invalid' });
}
// More validations here...
next();
}
The example above won't scale very well (probably should write a more general validator middleware to be shared among APIs) but hopefully it can still provide a helpful idea.
Upvotes: 2