Richard B
Richard B

Reputation: 935

MongoDB Aggregation pipeline problems

I'm new to mongoDB and am having difficulty getting my head around aggregation pipelines.

I have created a database that holds information regarding my stock trading. In a cut down version one document from my portfolio collection looks a bit like this

   {
   "date" : 2015-12-31T15:50:00.000Z,
   "time" : 1550,
   "aum"  : 1000000,
   "basket" :[
   {
     "_id" : "Microsoft",
     "shares" : 10,
     "price"  : 56.53,
     "fx"     : 1.0
   },
   .
   .
   .
   {
     "_id" : "GOOG.N",
     "shares" : 20,
     "price"  : 759.69,
     "fx"     : 1.0
   }

]

So, for each day, I keep track of my assets under management (aum) and a list of all the positions I hold with the current price. What I need to do is to calculate the daily net and gross exposure for the portfolio as a percentage of aum. Net exposure is simply:

sum(shares*price*fx)/aum

over all the stocks. Gross exposure is:

abs(shares*price*fx)/aum

(a negative position means a short position). I need to do this as a single query using the aggregation framework. I have tried numbers of queries but none seem to work so clearly I'm just wandering around in the dark. Can anyone give some guidance?

My query looks like this

db.strategy.aggregate(

  // Pipeline
  [
    // Stage 1
    {
      $project: {
        "_id": 0,
        "date":1,
        "time":1,
        "aum":1,
        "strategyName":1,
        "gExposure": {$divide: ["$grossExposure","$aum"]}
      }
    },

    // Stage 2
    {
      $group: {
        _id :{ date:"$date",time:"$time",strategyName:"$strategyName"},
        grossExposure: { $sum: { $abs: {$multiply: [ "$basket.sysCurShares","$basket.price","$basket.fx" ] } }}
      }
    },

    // Stage 3
    {
      $sort: {
      "_id.date": 1,  "_id.time": 1,  "_id.strategyName": 1 
      }
    }

  ]
);

The query runs but the calculated value is zero. My projection isn't working as I'd expect either as I would like all the data flattened to a two dimensional table.

Upvotes: 1

Views: 1429

Answers (2)

Shubham
Shubham

Reputation: 1426

you can do the same with mongodb 3.4 in single stage

db.strategy.aggregate([
{
  $project:{
        "date": 1,
        "time": 1,          
        "strategyName": 1,   
        "netExposure":{ "$divide": [{"$reduce":{input:"$basket",initialValue:0,in:{$add:[{$multiply: ["$$this.fx","$$this.shares","$$this.price"]},"$$value"]}}}, "$aum"] },
        "grossExposure":{"$abs":{ "$divide": [{"$reduce":{input:"$basket",initialValue:0,in:{$add:[{$multiply: ["$$this.fx","$$this.shares","$$this.price"]},"$$value"]}}}, "$aum"] }}
}, 
{ "$sort": { "date": 1,  "time": 1,  "strategyName": 1 } }
]);

Upvotes: 0

chridam
chridam

Reputation: 103455

Since the basket field is an array, you need to flatten it using $unwind before running the $group aggregate operation. Also, create a new field in the $project that holds the exposure before the $group pipeline. Continuing from your previous attempt, you could try the following pipeline:

db.strategy.aggregate([
    { "$unwind": "$basket" },
    {
        "$project": {
            "date": 1,
            "time": 1,          
            "strategyName": 1,
            "exposure": { 
                "$multiply": ["$basket.sysCurShares", "$basket.price", "$basket.fx"] 
            }
        }
    },    
    {
        "$group": {
            "_id": { 
                "date": "$date",
                "time": "$time",
                "strategyName": "$strategyName"
            },
            "totalExposure": { "$sum": "$exposure" },
            "aum": { "$first": "$aum" }
        }
    },
    {
        "$project": {
            "_id": 0,
            "date": "$_id.date",
            "time": "$_id.time",         
            "strategyName": "$_id.strategyName",
            "netExposure": { "$divide": ["$totalExposure", "$aum"] },
            "grossExposure": {
                "$abs": { "$divide": ["$totalExposure", "$aum"] } 
            }
        }
    }, 
    { "$sort": { "date": 1,  "time": 1,  "strategyName": 1 } }
]);

Upvotes: 2

Related Questions