I have a Mongoose Model:
/** USER MODEL */
const UserSchema = new mongoose.Schema(
{
username: {
type: String,
unique: true,
},
password: {
type: String,
min: 5
},
wallets: [{
name: {
type: String,
required: true
},
balance: {
type: Number,
required: true
}
}],
transactions: [{
type: {
type: String,
enum: ['expense', 'income']
},
label: {
type: String,
required: true
},
amount: {
type: Number,
required: true
},
category: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
wallet: {
type: String,
required: true
}
}],
},
{ timestamps: true }
)
** THE CONTROLLER **
export const addTransaction = async (req, res) => {
try {
const { id } = req.params;
const transaction = req.body.transaction
const user = await User.findById(id)
console.log(transaction.wallet)
const wallet = await User.find(
{ "wallets.name": transaction.wallet })
console.log(wallet)
await User.findByIdAndUpdate(id, { $push: { transactions:
transaction } })
res.status(200).json(user);
} catch (err) {
res.status(404).json({ message: err.message });
}
}
req.body.transaction has:
- amount // transaction amount that i want to subtract wallet balance with
- label // not needed in wallet calc
- wallet // the name of the wallet that needs to be accesed to change its balance
When a Transaction is made i get the Amount. I then need to subtract that amount from the wallets balance. Through req.body i get the walletname as well as the amount.
I need a mongoose query to find the wallet in User.wallets and edit its balance.
I have tried findByIdAndUpdate, find, findOne, findbyId, $set:
User.findByIdAndUpdate(id, {$set: {"wallets.amount": transaction.amount}})
User.findByIdAndUpdate(id, { wallets: { name: transaction.wallet { amount: transaction.amount} }})
also the User.find function i used above in the controller returns the whole user but the wallets is : [[Object], [Object], [Object], [Object]]
But i don’t think i used em correctly.
2
Answers
First of all, need to find the related
wallet
element from thewallets
array and then set the new value to itsbalance
field. For this:Find the wallet filtering by its
name
field and_id
field of theUser
modelThen update the only first found wallet element’s
balance
field by using Positional Operator ($
)Here is the DEMO Link for the
single wallet update
As another option, if you would like to update all the wallets which have the same
name
:For multiple element updates, use arrayFilters to filter multiple elements
Then use Filtered Positional Operator (
$[<identifier>]
to update all filtered wallet elements.Here is the DEMO Link for the
multiple wallet update
Hope, it’s clear and helpful
You can do this in a single
findOneAndUpdate
operation._id
and wherewallets.name
equal totransaction.wallet
.$push
thetransaction
to the userstransactions
array.$inc
rement thebalance
on the array element matching the$
positional operator found in the filter stage by a negative amount, effectively subtracting it.See HERE for a full working example.
The
findOneAndUpdate
can take an aggregation pipeline so you can perform more complex updates but since all you need to do is push to an array and deduct a value I’ve kept it simple.