$facet (aggregation)

Definition

  • $facet

New in version 3.4.

Processes multiple aggregation pipelines within a single stage on the same set ofinput documents. Each sub-pipeline has its own field in the outputdocument where its results are stored as an array of documents.

The $facet stage allows you to create multi-faceted aggregationswhich characterize data across multiple dimensions, or facets,within a single aggregation stage. Multi-faceted aggregationsprovide multiple filters and categorizations to guide data browsingand analysis. Retailers commonly use faceting to narrow search resultsby creating filters on product price, manufacturer, size, etc.

Input documents are passed to the $facet stage only once.$facet enables various aggregations on the same set of inputdocuments, without needing to retrieve the input documents multipletimes.

The $facet stage has the following form:

  1. { $facet:
  2. {
  3. <outputField1>: [ <stage1>, <stage2>, ... ],
  4. <outputField2>: [ <stage1>, <stage2>, ... ],
  5. ...
  6.  
  7. }
  8. }

Specify the output field name for each specified pipeline.

Behavior

Facet-related aggregation stages categorize and group incomingdocuments. Specify any of the following facet-related stages withindifferent $facet sub-pipeline’s <stage> to perform amulti-faceted aggregation:

Otheraggregation stages canalso be used with $facet with the following exceptions:

Each sub-pipeline within $facet is passed the exact same set ofinput documents. These sub-pipelines are completely independent of oneanother and the document array output by each is stored in separatefields in the output document. The output of one sub-pipeline can notbe used as the input for a different sub-pipeline within the same$facet stage. If further aggregations are required, add additionalstages after $facet and specify the field name, <outputField>,of the desired sub-pipeline output.

Example

Consider an online store whose inventory is stored in the followingartwork collection:

  1. { "_id" : 1, "title" : "The Pillars of Society", "artist" : "Grosz", "year" : 1926,
  2. "price" : NumberDecimal("199.99"),
  3. "tags" : [ "painting", "satire", "Expressionism", "caricature" ] }
  4. { "_id" : 2, "title" : "Melancholy III", "artist" : "Munch", "year" : 1902,
  5. "price" : NumberDecimal("280.00"),
  6. "tags" : [ "woodcut", "Expressionism" ] }
  7. { "_id" : 3, "title" : "Dancer", "artist" : "Miro", "year" : 1925,
  8. "price" : NumberDecimal("76.04"),
  9. "tags" : [ "oil", "Surrealism", "painting" ] }
  10. { "_id" : 4, "title" : "The Great Wave off Kanagawa", "artist" : "Hokusai",
  11. "price" : NumberDecimal("167.30"),
  12. "tags" : [ "woodblock", "ukiyo-e" ] }
  13. { "_id" : 5, "title" : "The Persistence of Memory", "artist" : "Dali", "year" : 1931,
  14. "price" : NumberDecimal("483.00"),
  15. "tags" : [ "Surrealism", "painting", "oil" ] }
  16. { "_id" : 6, "title" : "Composition VII", "artist" : "Kandinsky", "year" : 1913,
  17. "price" : NumberDecimal("385.00"),
  18. "tags" : [ "oil", "painting", "abstract" ] }
  19. { "_id" : 7, "title" : "The Scream", "artist" : "Munch", "year" : 1893,
  20. "tags" : [ "Expressionism", "painting", "oil" ] }
  21. { "_id" : 8, "title" : "Blue Flower", "artist" : "O'Keefe", "year" : 1918,
  22. "price" : NumberDecimal("118.42"),
  23. "tags" : [ "abstract", "painting" ] }

The following operation uses MongoDB’s faceting features to providecustomers with the store’s inventory categorized across multipledimensions such as tags, price, and year created. This$facet stage has three sub-pipelines that use$sortByCount, $bucket, or$bucketAuto to perform this multi-faceted aggregation.The input documents from artwork are fetched from the database onlyonce, at the beginning of the operation:

  1. db.artwork.aggregate( [
  2. {
  3. $facet: {
  4. "categorizedByTags": [
  5. { $unwind: "$tags" },
  6. { $sortByCount: "$tags" }
  7. ],
  8. "categorizedByPrice": [
  9. // Filter out documents without a price e.g., _id: 7
  10. { $match: { price: { $exists: 1 } } },
  11. {
  12. $bucket: {
  13. groupBy: "$price",
  14. boundaries: [ 0, 150, 200, 300, 400 ],
  15. default: "Other",
  16. output: {
  17. "count": { $sum: 1 },
  18. "titles": { $push: "$title" }
  19. }
  20. }
  21. }
  22. ],
  23. "categorizedByYears(Auto)": [
  24. {
  25. $bucketAuto: {
  26. groupBy: "$year",
  27. buckets: 4
  28. }
  29. }
  30. ]
  31. }
  32. }
  33. ])

The operation returns the following document:

  1. {
  2. "categorizedByYears(Auto)" : [
  3. // First bucket includes the document without a year, e.g., _id: 4
  4. { "_id" : { "min" : null, "max" : 1902 }, "count" : 2 },
  5. { "_id" : { "min" : 1902, "max" : 1918 }, "count" : 2 },
  6. { "_id" : { "min" : 1918, "max" : 1926 }, "count" : 2 },
  7. { "_id" : { "min" : 1926, "max" : 1931 }, "count" : 2 }
  8. ],
  9. "categorizedByPrice" : [
  10. {
  11. "_id" : 0,
  12. "count" : 2,
  13. "titles" : [
  14. "Dancer",
  15. "Blue Flower"
  16. ]
  17. },
  18. {
  19. "_id" : 150,
  20. "count" : 2,
  21. "titles" : [
  22. "The Pillars of Society",
  23. "The Great Wave off Kanagawa"
  24. ]
  25. },
  26. {
  27. "_id" : 200,
  28. "count" : 1,
  29. "titles" : [
  30. "Melancholy III"
  31. ]
  32. },
  33. {
  34. "_id" : 300,
  35. "count" : 1,
  36. "titles" : [
  37. "Composition VII"
  38. ]
  39. },
  40. {
  41. // Includes document price outside of bucket boundaries, e.g., _id: 5
  42. "_id" : "Other",
  43. "count" : 1,
  44. "titles" : [
  45. "The Persistence of Memory"
  46. ]
  47. }
  48. ],
  49. "categorizedByTags" : [
  50. { "_id" : "painting", "count" : 6 },
  51. { "_id" : "oil", "count" : 4 },
  52. { "_id" : "Expressionism", "count" : 3 },
  53. { "_id" : "Surrealism", "count" : 2 },
  54. { "_id" : "abstract", "count" : 2 },
  55. { "_id" : "woodblock", "count" : 1 },
  56. { "_id" : "woodcut", "count" : 1 },
  57. { "_id" : "ukiyo-e", "count" : 1 },
  58. { "_id" : "satire", "count" : 1 },
  59. { "_id" : "caricature", "count" : 1 }
  60. ]
  61. }