Devographics/state-of-js-graphql-results-api

Mongo Aggregation Help: Facets Breakdown

Closed this issue · 0 comments

Currently, you can search for e.g. the age range distribution of survey respondents and get data that looks like this:

{
  "data": {
    "survey": {
      "demographics": {
        "age": {
          "year": {
            "buckets": [
              {
                "id": "range_less_than_10",
                "count": 3,
                "percentage": 0
              },
              {
                "id": "range_10_18",
                "count": 95,
                "percentage": 1.5
              },
              {
                "id": "range_18_24",
                "count": 678,
                "percentage": 10.4
              },
              {
                "id": "range_25_34",
                "count": 3289,
                "percentage": 50.6
              },
              {
                "id": "range_35_44",
                "count": 1901,
                "percentage": 29.2
              },
              {
                "id": "range_45_54",
                "count": 433,
                "percentage": 6.7
              },
              {
                "id": "range_55_64",
                "count": 83,
                "percentage": 1.3
              },
              {
                "id": "range_more_than_65",
                "count": 18,
                "percentage": 0.3
              }
            ]
          }
        }
      }
    }
  }
}

You can also filter this by e.g. gender to limit the results to women.

But I would like to add an option to group the results by gender (or any other demographic "facet" – not sure if that's the proper term by the way?). So the resulting data would look something like this:

{
  "data": {
    "survey": {
      "demographics": {
        "age": {
          "year": {
            "facets": [
              {
                "type": "gender", // could be "country", "age", "salary", etc.
                "id": "female", // the value we're currently grouping by
                "buckets": [
                  {
                    "id": "range_less_than_10",
                    "count": 3,
                    "percentage": 0
                  },
                  {
                    "id": "range_10_18",
                    "count": 95,
                    "percentage": 1.5
                  },
                  {
                    "id": "range_18_24",
                    "count": 678,
                    "percentage": 10.4
                  },
                  {
                    "id": "range_25_34",
                    "count": 3289,
                    "percentage": 50.6
                  },
                  {
                    "id": "range_35_44",
                    "count": 1901,
                    "percentage": 29.2
                  },
                  {
                    "id": "range_45_54",
                    "count": 433,
                    "percentage": 6.7
                  },
                  {
                    "id": "range_55_64",
                    "count": 83,
                    "percentage": 1.3
                  },
                  {
                    "id": "range_more_than_65",
                    "count": 18,
                    "percentage": 0.3
                  }
                ]
              },
              {
                "type": "gender",
                "id": "male",
                "buckets": [
                  {
                    "id": "range_less_than_10",
                    "count": 3,
                    "percentage": 0
                  },
                  {
                    "id": "range_10_18",
                    "count": 95,
                    "percentage": 1.5
                  }
                  // etc.
                ]
              },

              {
                "type": "gender",
                "id": "non_binary",
                "buckets": [
                  // ...
                ]
              }
            ]
          }
        }
      }
    }
  }
}

The current Mongo aggregation pipeline is fairly simple:

const pipeline = [
            {
                $match: match
            },
            {
                $unwind: {
                    path: `$${key}`
                }
            },
            {
                $group: {
                    _id: {
                        id: `$${key}`,
                        year: '$year'
                    },
                    count: { $sum: 1 }
                }
            },
            {
                $project: {
                    _id: 0,
                    id: '$_id.id',
                    year: '$_id.year',
                    count: 1
                }
            },
            { $sort: { [sort]: order } }
        ]

I'm guessing I need to add a second $group stage, but I'm not quite sure how to do it…

Also note that the facet that items are grouped by will be set dynamically (or can be empty, in which case the facets array would just contain a single element with "type": "default" and "id": "default").