So I have this data stored in a mongodb database:
{
_id: 'string',
email: 'string',
purchases: [
{ name: 'item 1', cost: 45, quantity: 3 },
{ name: 'item 2', cost: 62, quantity: 2 },
{ name: 'item 3', cost: 14, quantity: 7 },
]
}
What I am trying to do is search for the user id (._id) and the item in the purchases array by the item name, so for item 1:
{ _id: req.body._id, purchases: { $elemMatch: { name: 'Item 1' }}}
This query works fine. However the behavior I need is if the item exists, modify the quantity value to reset to one. If the item doesn't exist, i.e. its a new item, I want to insert a new item object.
I thought that .findOneAndReplace would work for this, so my code is:
User.findOneAndReplace(
{ _id: req.body._id, purchases: { $elemMatch: { name: 'Item 1' }}},
{ $push: { purchases: { name: req.body.name, cost: req.body.cost, quantity: 1 }}},
{
upsert: true
}
).then((result) => {
res.status(200).json({
message: 'Added score :D'
})
}).catch((error) => {
res.status(400).json({
message: 'Failed to add score...' error
})
})
but this obviously doesn't work. I can insert a new value into the purchases array but I cant update a current result if it exists.
CodePudding user response:
What you are doing is actually not a good way to handle documents.
A better way to handle your problem is to create a different model for purchases.
const purchases = mongoose.Schema({
name: String,
cost: Number,
quantity: Number,
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
})
Instead of adding purchases to the User model, you will create a new entry under purchases.
To update purchases, you can just update each purchase document directly.
If you want to retrieve all purchases for a user, you can simply
Purchases.find({ user: user._id })
To see if item exist.
Purchases.find({ user: user._id, name: 'Item 1'});
You can also find the purchases through the user model using $lookup.
Users.aggregate([
{
$match: { _id: user._id }
},
{
$lookup: {
from: 'purchases',
localField: "_id",
foreignField: "user",
as: "purchases"
}
},
{
$project: {
....fields you want to return ....
}
}
])
In the long run you will find this model of database more efficient and easier to up keep, and there's more pros than cons separating the documents into different collections.
