Home
Tags:

unwind

Unwinds an array.
Each item in the arr becomes a document.

# input
db.movies.find({title: "Baby's Dinner"}, { _id: 0, cast: 1})
# returns
{cast: ["Mrs. Auguste Lumiere","Andre Lumire","Auguste Lumire"]}


# unwind each cast mmember into its own doc with the title
db.movies.aggregate([
  {$match: {title: "Baby's Dinner"}},
  {$unwind: "$cast"},
  {$project: { title: 1, _id: 0, "cast": 1 }}
])

# returns...
{ "title" : "Baby's Dinner", "cast" : "Mrs. Auguste Lumiere" }
{ "title" : "Baby's Dinner", "cast" : "Andre Lumi�re" }
{ "title" : "Baby's Dinner", "cast" : "Auguste Lumi�re" }

Can be helpful for grouping on array entries

Grouping movies based on year AND genres is complex.
Array item order matters.

Example

Find

  • most popular genre
    • grouped by year
    • from 2010-2015
    • with runtime of greater-than 90 min
    • movies that have been rated
db.movies.aggregate([
  {
  $match: {
    'imdb.rating': {
        $gte: 0,
      },
      year: { $gte: 2010, $lte: 2015 },
      runtime: { $gte: 90 },
    },
  },
  {
    $unwind: '$genres',
  },
  {
    $group: {
      _id: {
        year: '$year',
        genre: '$genres',
      },
      avg_rating: { $avg: '$imdb.rating' },
    },
  },
  {
    $sort: {
      '_id.year': -1,
      avg_rating: -1,
    },
  },
  {
    $group: {
      _id: '$_id.year',
      genre: { $first: '$_id.genre' },
      avg_rating: { $first: '$avg_rating' },
    },
  }{
    $sort: { _id: -1}
  }
])
  • the group stage
    • group by year
    • already sorted in the order needed
    • take FIRST item of each group & set to the genre + average rating
  • sort
    • return in the order desired

returns docs like...

{_id: 2015, genre: "Biography", avg_rating: 7.9}
{_id: 2013, genre: "Documentary", avg_rating: 7.4}

...etc

NOTE: unwinding on large documents may cause performance issues.

There is a long form

{
  $unwind : {
    path: `array-path-to-unwind`,
    includeArrayIndex: `name of new field that will contain the array index value`,
    preserveNullAndEmptyArrays: <bool>
  }
}

# this could be used like...
db.movies.aggregate([
{$match: {title: "Baby's Dinner"}},
{$unwind: {
  path: "$cast",
  includeArrayIndex: "idx",
}},
{$project: { title: 1, _id: 0, "cast": 1 }}
])

# returns...

{ "title" : "Baby's Dinner", "cast" : "Mrs. Auguste Lumiere", idx: 0 }
{ "title" : "Baby's Dinner", "cast" : "Andre Lumi�re", idx: 1 }
{ "title" : "Baby's Dinner", "cast" : "Auguste Lumi�re", idx: 2 }