简体   繁体   中英

$aggregation, $sum on two collections in MongoDB

Hi suppose I have these two collections

sample1 :

 {
    "_id" : {
            "date" : ISODate("2020-02-11T18:30:00Z"),
            "price" : 4,
            "offer" : 0,
            "itemCode" : "A001"
            "customerId" : ObjectId("5e43de778b57693cd46859eb"),
            "sellerId" : ObjectId("5e43e5cdc11f750864f46820"),
      },
    "charges" : 168
  }
  {
    "_id" : {
            "date" : ISODate("2020-02-11T18:30:00Z"),
            "coverPrice" :5.5 ,
            "offer" : 38,
            "itemCode" : "B001"
            "customerId" : ObjectId("5e43de778b57693cd46859eb"),
            "sellerId" : ObjectId("5e43e5cdc11f750864f46820"),
    },
    "charges" : 209.5
  }

NOTE : sample1's _id doesnot have any ObjectId() .

sample2 :

        {
            "paymentReceivedOnDate" : ISODate("2020-02-12T18:30:00Z"),
             "customerId" : ObjectId("5e43de778b57693cd46859eb"),
            "sellerId" : ObjectId("5e43e5cdc11f750864f46820"),
            "amount" : 30,
         }
      {
            "paymentReceivedOnDate" : ISODate("2020-02-12T18:30:00Z"),
             "customerId" : ObjectId("5e43de778b57693cd46859eb"),
            "sellerId" : ObjectId("5e43e5cdc11f750864f46820"),
            "amount" : 160,
         }
     {
            "paymentReceivedOnDate" : ISODate("2020-02-11T18:30:00Z"),
             "customerId" : ObjectId("5e43de778b57693cd46859eb"),
            "sellerId" : ObjectId("5e43e5cdc11f750864f46820"),
            "amount" : 50,
        }

My problem statements :

1: Firstly i need to calculate the totalCharges from sample 1 collection. against the [date,customerId,sellerId ]

2: Secondly i need to calculate totalAmount from sample 2 collection.

3: Than i need calculte the outstanding ie [totalCharges - totalAmount].

4: lastly and most importantly i need to save the projected result into a new collection suppose "result" with the following fields-['customerId','sellerId','date','totalCharges','outstanding'(ie: [totalCharges - totalAmount]),'totalAmount'.

You can try below query :

db.sample1.aggregate([
    /** groups data & sum up charges */
    { $group: { _id: { date: '$_id.date', customerId: '$_id.customerId', sellerId: '$_id.sellerId' }, totalCharges: { $sum: '$charges' } } },
    /** finds matching docs from sample2 */
    {
        $lookup:
        {
            from: "sample2",
            let: { customerId: '$_id.customerId', sellerId: '$_id.sellerId' },
            pipeline: [
                {
                    $match:
                    {
                        $expr:
                        {
                            $and:
                                [
                                    { $eq: ["$customerId", "$$customerId"] },
                                    { $eq: ["$sellerId", "$$sellerId"] }
                                ]
                        }
                    }
                },
                { $project: { amount: 1, _id: 0 } }
            ],
            as: "TotalAmount" // TotalAmount is an array of objects, each object will have just amount field in it.
        }
    },
    /** retains only needed fields  */
    {
        $project: {
            totalCharges: 1, outstanding: {
                $subtract: ['$totalCharges', {
                    $reduce: {
                        input: '$TotalAmount',
                        initialValue: 0,
                        in: { $add: ["$$value", "$$this.amount"] }
                    }
                }]
            }, TotalAmount: {
                $reduce: {
                    input: '$TotalAmount',
                    initialValue: 0,
                    in: { $add: ["$$value", "$$this.amount"] }
                }
            }
        }
    }
])

Test : MongoDB-Playground

Ref : aggregation-pipeline

Note : At the end of the aggregation you can have either $merge or $out stage to write aggregation results into new collection, If your MongoDB v >= 4.2 then prefer $merge cause it will merge fields to existing documents/adds new documents to existing collection or if no collection is found with given name it would create new collection, But where as $out will completely replaces existing collection if provided collection name already exists or creates new collection with provided name.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM