Re: Wide to long transformation in aggregation

From: Kevin Adistambha <kevinadi@xxxxxxxxxxx>
To: mongodb-user <mongodb-user@xxxxxxxxxxxxxxxx>
Date: Thu, 5 May 2016 20:37:25 -0700 (PDT)
Why ads?


Hi Boyd,

I noticed the $project to array is a 3.2+ feature, but I cannot find an 
example that is 2.6 compatible. Is there another route, or would 
denormalization be better?

It’s a bit different using 2.6 due to the limited operators available in 
the aggregation framework, but it can be done. This is tested on 2.6.11:

db.orders.aggregate(

  // Project the year and month of each order, conserving the activity type, into an array with single element
  {$group: {
    _id: "$order_no",
    order: {$push: 
      {year: {$year: "$order_dt"}, month: {$month: "$order_dt"}, type: {$literal: "order"}}
    },
    start: {$push:
      {year: {$year: "$start_dt"}, month: {$month: "$start_dt"}, type: {$literal: "start"}}
    },
    stop: {$push:
      {year: {$year: "$stop_dt"}, month: {$month: "$stop_dt"}, type: {$literal: "stop"}}
    },
    ship: {$push: 
      {year: {$year: "$ship_dt"}, month: {$month: "$ship_dt"}, type: {$literal: "ship"}}
    }
  }},

  // Project the activities of each order into a single array
  {$project: {
    _id: "$_id",
    activities: {$setUnion: ["$order", "$start", "$stop", "$ship"]}
  }},

  // Unwind the activities array
  {$unwind: "$activities"},

  // Project the activity types into separate fields
  {$project: {
    _id: {year: "$activities.year", month: "$activities.month"},
    order: {$cond: [ {$eq: ["$activities.type", "order"]}, 1, 0 ]},
    start: {$cond: [ {$eq: ["$activities.type", "start"]}, 1, 0 ]},
    stop:  {$cond: [ {$eq: ["$activities.type", "stop" ]}, 1, 0 ]},
    ship:  {$cond: [ {$eq: ["$activities.type", "ship" ]}, 1, 0 ]}
  }},

  // For each distinct Year-Month, calculate the total number of each activity
  {$group: {
    _id: "$_id",
    order: {$sum: "$order"},
    start: {$sum: "$start"},
    stop: {$sum: "$stop"},
    ship: {$sum: "$ship"}
  }},

  // Sort by Year-Month
  {$sort: {"_id.year": 1, "_id.month": 1}}
)

This query should have an identical output with the previous one:

{
  "_id": {
    "year": 2008,
    "month": 1
  },
  "order": 1,
  "start": 0,
  "stop": 0,
  "ship": 0
},
{
  "_id": {
    "year": 2008,
    "month": 2
  },
  "order": 1,
  "start": 0,
  "stop": 0,
  "ship": 0
},
{
  "_id": {
    "year": 2008,
    "month": 4
  },
  "order": 0,
  "start": 2,
  "stop": 1,
  "ship": 0
},
{
  "_id": {
    "year": 2008,
    "month": 5
  },
  "order": 0,
  "start": 0,
  "stop": 1,
  "ship": 0
},
{
  "_id": {
    "year": 2009,
    "month": 5
  },
  "order": 0,
  "start": 0,
  "stop": 0,
  "ship": 2
}

However, I must reiterate my earlier point that if you frequently need this 
aggregation, please consider using a pre-aggregated report 
<https://docs.mongodb.org/ecosystem/use-cases/pre-aggregated-reports/
instead.

Best regards,
Kevin


-- 
You received this message because you are subscribed to the Google Groups "mongodb-user"
group.

For other MongoDB technical support options, see: https://docs.mongodb.org/manual/support/
--- 
You received this message because you are subscribed to the Google Groups "mongodb-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mongodb-user+unsubscribe@xxxxxxxxxxxxxxxx.
To post to this group, send email to mongodb-user@xxxxxxxxxxxxxxxx.
Visit this group at https://groups.google.com/group/mongodb-user.
To view this discussion on the web visit https://groups.google.com/d/msgid/mongodb-user/28c3a8fc-02d7-4fc0-b16f-f21ee36702e1%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Why ads?