Mongoose Update Field With the Item of the Another Field That is Array

Viewed 65

I am building an Expense Tracker Application, There is a User Collection that has fields like Name, Amount, Expenses Array, Incomes Array, and So On.

My Database Is Mongo Db with Mongoose and the Server Is Written In Express.

Here Is A Screenshot Of the Database after The Values are Filled MongoDB Database Screenshot

I am trying to Implement a Route in which The User Can Delete an Expense and After Deleting the Expense I want to update the Balance and make the Balance = Balance + Expense. I am able to Delete and Expense But Not able to Update the Balance as I do not know how to retrieve the Balance from the Deleted Expense


Here is the Delete Route :

router.delete("/", (req, res) => {
  const { UserID, ExpenseID } = req.query;
  const query = {
    $pull: {
      Expenses: { _id: ExpenseID },
    },
  };
  User.findByIdAndUpdate(UserID, query)
  
});

I want to add a Mongoose Method which Will Fetch the Expense Amount from the Received Expense Id and Store it in a variable and After the Expense Gets Deleted, I want to call a method to update the balance of the User in the Promise.

Here is an example of what I intend to do

// Deletes An Expense
router.delete("/", (req, res) => {
  const { UserID, ExpenseID } = req.query;
  const query = {
    $pull: {
      Expenses: { _id: ExpenseID },
    },
  };
  User.find({/*Some Query Which Will Return me The Provided Expense ID's Amount*/})
  User.findByIdAndUpdate(UserID, query)
  .then(() => {
    // Once I find and Remove the Expense, Now I would Like to Update the Users Balance
    // NewBalance = OldBalance + Expense ID's Amount Returned by the Find Method
    // Here I would Call another User.find method to update the Users Balance
  })
});

Let's Say From the Above Database Snap, I want to delete the Expenses (Starting From 0) 1st Object Element, Name: Uber Fare, I will send the Object Id which is 6091f725403c2e1b8c18dda3 to the Server and should Expect my Balance to Increase from 48495 to 49695

2 Answers

What you can do is:

  1. Fetch user document with UserID
  2. Find the expense with ExpenseID
  3. Update the Balance with the expense amount
  4. Remove expense from Expenses array
  5. Save user document
router.put("/", async (req, res) => {
  try {
    const { UserID, ExpenseID } = req.query;
    let user = await User.find({ _id: UserID });
    index = user.Expenses.findIndex((expense) => expense._id === ExpenseID);
    if (index != -1) {
      user.Balance += user.Expenses[index].Amount;
      user.Expenses.splice(index, 1);
    }
    await user.save();
    return res.status(200).json({ success: true, user: user });
  } catch (error) {
    return res.status(400).json({ success: false, error: error })
  }
});

NOTE: Since this is updating the document, I configured put method instead of delete on the router.

Create a static method for the schema like so

userSchema.statics.deleteExpenseUpdateBalance = async function (userID, expenseID) {
  const user = await this.findOne({ _id: userID });
  let userExpenses = user.Expenses;
  userExpenses.forEach((expense) => {
    if (expense._id === expenseID) {
      let amount = expense.Amount;
      let index = userExpenses.indexOf(expense);
      userExpenses.splice(index, 1);
      user.Balance += amount;
      return;
    }
  });

  user.save((err) => {
      if (err) {
          console.log(err)
      }
  });
};

Access this in your route handler

router.delete("/", async (req, res) => {
  const { UserID, ExpenseID } = req.query;
  let result = await User.deleteExpenseUpdateBalance(UserID, ExpenseID)
});

This static method will remove the expense and update the balance. Explanation: The static method just finds the user and iterates through their Expenses and removes the required expense and the amount is just added to the balance. Finally the user.save() method is called to save all documents.

NOTE: Use this only if you are sure that the expenseID exists in the Expense array, otherwise you'll just have to add an extra check for that in the static method

Also put the static method in the file where you create your schema and model in between both of their creations i.e after you've created the userSchema and before you finalise it into a model.

Related