'How to process the fetched data from mongoDB?

I want my order_total to be calculated from results after joining two different collections

I'm building an Food Ordering App. I've seperate model for item:"ItemModel"

Here's my orderSchema which is being followed while ordering the items. I've referred to the ItemModel in case of Item_Id

My OrderSchema:

const cartOrderSchema = new mongoose.Schema({
  items: [
    {
      item_id: { type: mongoose.Schema.Types.ObjectId, ref: "itemModel" },
      quantity: { type: Number, default: 1 },
    },
  ],
  user_id: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "userModel",
  },
  date: {
    type: Date,
    default: new Date(),
  },
  order_total: {
    type: Number,
    default: 0,
  },
  delivery_address: {
    type: String,
    default: "GGn",
  },
  payment_type: {
    type:String,
    default:"Cash"
  },
});

I'm using this query:

   await req.user.populate({
      path: "mycartOrder",
      populate:{
        path:"items.item_id"
      }
    });
    res.status(200).send(req.user.mycartOrder);

& getting result as:

{
        "order_total": 0,
        "delivery_address": "GGn",
        "payment_type": "Cash",
        "_id": "6270d84d89e3be5f291ee923",
        "items": [
            {
                "item_id": {
                    "item_type": "Veg",
                    "_id": "62614934693ffd8d8f7979e9",
                    "name": "Cheese Burger",
                    "cuisine_category": "Starters",
                    "price": 67,
                    "description": "Aloo patty enclosed within Bun Tikki with melted cheese",
                    "store_id": "626148ca693ffd8d8f7979e2",
                    "__v": 0
                },
                "quantity": 10,
                "_id": "6270d84d89e3be5f291ee924"
            },
            {
                "item_id": {
                    "item_type": "Veg",
                    "_id": "62614977693ffd8d8f7979ec",
                    "name": "Paneer Lababdar",
                    "cuisine_category": "Indian",
                    "price": 249,
                    "description": "Panner vegetable cooked in very rich Gravy",
                    "store_id": "626148ca693ffd8d8f7979e2",
                    "__v": 0
                },
                "quantity": 3,
                "_id": "6270d84d89e3be5f291ee925"
            }
        ],
        "date": "2022-05-03T07:22:03.907Z",
    },

What I want?

I want that this order_total should be calculated automatically when the query is executed by multiplying the item's price with quantity.

Please HELP!!



Solution 1:[1]

If your collection is called cart (I'm not familiar with node.js or mongoose), you can use the $unwind operator and unwind your items. Then use the $addFields operator to add a new field overwriting your order_total, with the value to be the multiplication of the price and quantity. Then you'll have to group them back together, using the $sum operator on all the order_total fields, and then re-add all the previous fields..

db.cart.aggregate([
    {
        $unwind: "$items"
    },
    {
        $addFields: {
            "order_total": {
                $multiply: [ "$items.quantity", "$items.item_id.price" ]
            }
        }
    }, 
    {
        $group: {
            _id: "$_id",
            order_total: {$sum: "$order_total"},
            delivery_address: { $first: "$delivery_address" },
            payment_type: { $first: "$payment_type" },
            items: { $push: "$items" },
            date: {$first: "$date" }
        }
    }
])

You can skip the $addFields step and do the sum and multiply all in one step but I wanted to show both for clarity:

db.cart.aggregate([
    {
        $unwind: "$items"
    }, 
    {
        $group: {
            _id: "$_id",
            order_total: {$sum: {$multiply: [ "$items.quantity", "$items.item_id.price" ]}},
            delivery_address: { $first: "$delivery_address" },
            payment_type: { $first: "$payment_type" },
            items: { $push: "$items" },
            date: {$first: "$date" }
        }
    }
])

You might need a match stage if you only want one specific cart.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 DFW