$Subtract and other artihmetic operators returning Object instead of int

Problem

  • I made some code to perform arithmetic operations as I am working on billing software.
  • This code snippet
await shopCollection.updateOne(
        { Barcode: elem.Barcode },
        {
          $set: {
            Quantity: { $subtract: ["$Quantity", -elem.Quantity] },
            SalesQuantity: {
              $add: [{ $ifNull: ["$SalesQuantity", 0] }, elem.Quantity],
            },
            Profit: { $subtract: ["$SalesPrice", "$CostPrice"] },
            TotalProfit: {
              $add: ["$TotalProfit", { $multiply: ["$Profit", elem.Quantity] }],
            },
            SalesTotal: {
              $add: [
                "$SalesTotal",
                { $multiply: ["$SalesPrice", elem.Quantity] },
              ],
            },
          },
        },
        { upsert: true, returnOriginal: false }
      );
Entire node js Function
  const items = req.body.Items;
  const PhoneNumber = req.body.phoneno;
  const paymentMethod = req.body.paymentMethod;

  let failureArr = [],
    billingData = [],
    TotalAmount = 0,
    TotalProfit = 0;

  for(let j = 0;j<items.length;j++){
    const elem = items[j];
    try {
      const doc = await shopCollection.findOne({ Barcode: elem.Barcode });
      if (!doc) {
        failureArr.push({ message: "cant find barcode " + elem.Barcode });
        return;
      }

      await shopCollection.updateOne(
        { Barcode: elem.Barcode },
        {
          $set: {
            Quantity: { $subtract: ["$Quantity", -elem.Quantity] },
            SalesQuantity: {
              $add: [{ $ifNull: ["$SalesQuantity", 0] }, elem.Quantity],
            },
            Profit: { $subtract: ["$SalesPrice", "$CostPrice"] },
            TotalProfit: {
              $add: ["$TotalProfit", { $multiply: ["$Profit", elem.Quantity] }],
            },
            SalesTotal: {
              $add: [
                "$SalesTotal",
                { $multiply: ["$SalesPrice", elem.Quantity] },
              ],
            },
          },
        },
        { upsert: true, returnOriginal: false }
      );

      const updatedDoc = await shopCollection.findOne({ Barcode: elem.Barcode });

      billingData.push({
        Product: updatedDoc.Product,
        Price: updatedDoc.SalesPrice,
        Quantity: elem.Quantity,
        Amount: elem.Quantity * updatedDoc.SalesPrice,
      });
      TotalAmount += elem.Quantity * updatedDoc.SalesPrice;
      TotalProfit += (doc.CostPrice - updatedDoc.SalesPrice) * elem.Quantity;
    } catch (err) {
      failureArr.push({
        code: err,
        message: `failed to subtract quantity from ${elem.Barcode}`,
      });
    }
  };

  const date = new Date();
  const day = date.getDate().toString().padStart(2, "0");
  const month = (date.getMonth() + 1).toString().padStart(2, "0");
  const year = date.getFullYear().toString().slice(-2);
  const formattedDate = `${day}-${month}-${year}`;

  const filter = { date: formattedDate };

const setOnInsertUpdate = {
  $setOnInsert: {
    Date: formattedDate,
    Volume: 0,
    Profit: 0,
    Customers: 0,
    Log: [],
  }
};

const incAndPushUpdate = {
  $inc: {
    Customers: 1,
    Volume: TotalAmount,
    Profit: TotalProfit,
  },
  $push: {
    Log: {
      Bill: billingData,
      Amount: TotalAmount,
      Profit: TotalProfit,
      Id: PhoneNumber ? PhoneNumber : "Unknown",
    },
  },
};

const options = { upsert: true, returnOriginal: false };

// find the entry and update or create it
shoppingLog.findOneAndUpdate(filter, setOnInsertUpdate, options)
  .then(() => {
    return shoppingLog.findOneAndUpdate(filter, incAndPushUpdate, options);
  })
  .catch((err) => {
    console.error(err);
  });


  if (PhoneNumber) {
    const upd1 = {
      $set: {
        LastVisited: formattedDate,
        TimesVisited: {
          $add: [{ $ifNull: ["$TimesVisited", 0] }, 1],
        },
        PurchaseVolume: {
          $add: [{ $ifNull: ["$PurchaseVolume", 0] }, TotalAmount],
        },
        Profit: {
          $add: [{ $ifNull: ["$Profit", 0] }, TotalProfit],
        },
      },
      $push: {
        Log: {
          Bill: billingData,
          Amount: TotalAmount,
          Profit: TotalProfit,
          Id: PhoneNumber ? PhoneNumber : "Unknown",
          Method: paymentMethod,
        },
      },
    };

    const opts = { returnOriginal: false };

    // find the entry and update or create it
    usersCollection.findOneAndUpdate(
      { PhoneNumber: PhoneNumber },
      upd1,
      opts,
      function (err, result) {
        if (err) {
          failureArr.push({
            message: "Updaing UsersCollection Failed",
            code: err,
            result,
            upd1,
          });
        }
      }
    );
  }

  if (failureArr.length === 0) {
    return res
      .status(200)
      .json({ message: "Success", billingData, TotalAmount });
  } else {
    return res.status(400).json({
      message: "Somestuff failed",
      billingData,
      failureArr,
      TotalAmount,
    });
  }
});
But this makes a Obejct turn like so rather than a integer value

Here's a comparison before and after running the function

index

To update a document while referring to other fields you need to use the aggregation syntax.

Few things about your code.

You return if findOne fails but then you updateOne with upsert:true. The only time the document will be upserted is if findOne succeed and then some other process/thread deletes the said document before the updateOne starts. But in this rare case your $set will not make sense as there will be no fields named, SalesPrice, CostPrice.

I do not see any option for updateOne that looks like returnOriginal, there is some close to that for findOneAndUpdate but it is named returnNewDocument which might be much better that doing a 3rd access to the database with the findOne that follows.