skip to Main Content

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


  1. First of all, need to find the related wallet element from the wallets array and then set the new value to its balance field. For this:

    User.findOneAndUpdate(
    {
      _id: id,
      "wallets.name": transaction.wallet
    },
    {
      $set: {
        "wallets.$.balance": transaction.amount
      }
    })
    

    Find the wallet filtering by its name field and _id field of the User model
    Then 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:

    User.findOneAndUpdate(
    {
      _id: id
    },
    {
      $set: {
         "wallets.$[wallets].balance": transaction.amount
    },
    {
      "arrayFilters": [
        {
         "wallets.name": transaction.wallet
        }
      ]
    })
    

    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

    Login or Signup to reply.
  2. You can do this in a single findOneAndUpdate operation.

    1. Find the user by _id and where wallets.name equal to transaction.wallet.
    2. $push the transaction to the users transactions array.
    3. $increment the balance on the array element matching the $ positional operator found in the filter stage by a negative amount, effectively subtracting it.
    const user = await User.findOneAndUpdate(
       {
          _id: id, 
         'wallets.name': transaction.wallet
       },
       {
          $push: {
             'transactions': transaction
          },
          $inc: {
             'wallets.$.balance': -transaction.amount    
          }
       },
       { new: true } 
    );
    

    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search