Machine Learning & Big Data Blog

How To Use MongoDB $unwind

6 minute read
Shanika Wickramasinghe

MongoDB $unwind is a useful tool in performing aggregation in MongoDB. Let’s take a look at $unwind and how to use it.

(This article is part of our MongoDB Guide. Use the right-hand menu to navigate.)

What is MongoDB $unwind?

The MongoDB $unwind operator is used to deconstruct an array field in a document and create separate output documents for each item in the array.

The only difference between the input document and output documents is that, in output documents, the value of the array field is replaced by a single item from the input document array. You will see this as I walk you through this example.

MongoDB $unwind transforms complex documents into simpler documents, which increase readability and understanding. This also allows us to perform additional operations, like grouping and sorting on the resulting output.

The basic syntax of $unwind operator

{ $unwind: "$<field path/ array path>" }
{$unwind: { path : "$<field path/ array path>", <optional arguments>}}

Here, you should prefix the path with the dollar sign “$” for a successful $unwind operation.

Next, we will demonstrate a simple $unwind operation using our “vehicledetails” collection. First, let’s have a look at our collection.

db.vehicledetails.find().pretty()

Result:

Next, we use the $unwind operator to deconstruct the “model_year” array field and to create separate documents for each year.

db.vehicledetails.aggregate([{$unwind : "$model_year" }]).pretty()

Result:

As shown in the above output, a new document is created for each item in the “model_year” array.

How $unwind works with non-array field paths

Before MongoDB 3.2, if a non-array field is defined as the path in the $unwind operator, it would have resulted in an error. From MongoDB 3.2 onwards, any non-array field which does not resolve to a missing, null, or empty array will be treated as a single element array.

This next example shows how the $unwind operator handles a single element array.

db.vehicledetails.aggregate([{$unwind : "$make" }]).pretty()

Result:

Here, the $unwind operation successfully creates a single output document as it considers the “make” field as a single item array.

Missing field as the path

The $unwind operator will not generate any output if the specified path is a missing/unavailable field. There will be no error as the $unwind will ignore the input document.

db.vehicledetails.aggregate([{$unwind : "$use" }]).pretty()

Result:

In the above operation, the provided path for the $unwind operator is the “use” field. However, the input document is ignored, as there is no “use” field in the input document.

$unwind operator options

The $unwind operator can be used with two optional arguments, which are includeArrayIndex and preserveNullAndEmptyArrays. This section will demonstrate how each option affects the result of an $unwind operation.

Again, we’ll use the “vehicledetails” collection with additional documents to demonstrate the functionality of the optional arguments.

db.vehicledetails.find().pretty()

Result:

When you perform $unwind operation on the above data set with the “model_year” field, the output will consist of five results.

Let’s see this in this example:

db.vehicledetails.aggregate([{$unwind : "$model_year" }]).pretty()

Result:

includeArrayIndex option

The includeArrayIndex option is used to obtain the array index with the $unwind operation output. We can define a field in the “includeArrayIndex” syntax to get the array index of each output document. If the array field is null, this will result in a null value in the user-defined field, and if an empty array is present, it will be ignored as there are no items in that array.

In the below example, the “model_year” field is used to carry out the $unwind operation, and the user-defined “vehicleIndex” field is used to capture the array index.

db.vehicledetails.aggregate([{$unwind : {path: "$model_year", includeArrayIndex: "vehicleIndex" }}]).pretty()

Result:

preserveNullAndEmptyArrays option

Defining the “preserveNullAndEmptyArrays” option in a $unwind operation allows the user to include documents where the array field is missing, null, or an empty array. The “preserveNullAndEmptyArrays” option only takes Boolean arguments like true or false.

Let’s use the documents within the “vehicledetails” collection to demonstrate “preserveNullAndEmptyArrays” option. This will result in an output where all missing, null, or empty arrays in the “model_year” field are captured.

db.vehicledetails.aggregate([{$unwind : {path: "$model_year", preserveNullAndEmptyArrays: true}}]).pretty()

Result:

Grouping data by Unwound values

In MongoDB, you can use the resulting dataset of a $unwind operation—unwound values—to further transform the data set.

The “vehiclesalesmain” collection is used to demonstrate how to combine $unwind operator with other functions.

db.vehiclesalesmain.find().pretty()

Result:

In the next section, the “colours” array is used to perform the $unwind operation. We also use MongoDB group and sort methods to get the average price according to the vehicle colours.

db.vehiclesalesmain.aggregate([{$unwind: {path: "$colours", preserveNullAndEmptyArrays: true}}, {$group: { _id: "$colours", averagePrice: {$avg: "$price"}}},{$sort: {"averagePrice": -1}}])

Result:

Let’s simplify the above formula in several steps to get a better understanding of the process. You can see the complete formatted syntax below.

db.vehiclesalesmain.aggregate([
{
$unwind: {
path: "$colours",
preserveNullAndEmptyArrays: true
}
},
{
$group: {
_id: "$colours",
averagePrice: {
$avg: "$price"
}
}
},
{
$sort: {
"averagePrice": -1
}
}
])

Step 1

In the first step, the documents in the “vehiclesalesmain” collection are unwound using the “colours” array field. Then the preserveNullAndEmptyArrays is set to true to capture any missing, null, or empty arrays in the resulting output.

db.vehiclesalesmain.aggregate([{$unwind: {path: "$colours", preserveNullAndEmptyArrays: true}}]).pretty()

Result:

Step 2

In the second step, documents resulting from the $unwind operation are grouped by the MongoDB group method using the colour, and the average price for each colour is calculated.

Grouping syntax:

{$group: { _id: "$colours", averagePrice: {$avg: "$price"}}}

Complete syntax:

db.vehiclesalesmain.aggregate([{$unwind: {path: "$colours", preserveNullAndEmptyArrays: true}}, {$group: { _id: "$colours", averagePrice: {$avg: "$price"}}}])

Result:

Step 3

Finally, the grouped data set is sorted in descending order using the MongoDB sort method.

Sorting syntax:

{$sort: {"averagePrice": -1}}])

Complete syntax:

db.vehiclesalesmain.aggregate([{$unwind: {path: "$colours", preserveNullAndEmptyArrays: true}}, {$group: { _id: "$colours", averagePrice: {$avg: "$price"}}},{$sort: {"averagePrice": -1}}])

Result:

Using $unwind on embedded arrays

When you perform the $unwind operation on an embedded array, it will function the same way as on a normal array field. The $unwind operation will deconstruct the items in each of the embedded arrays.

Using the “vehicleitems” collection, we will demonstrate how the $unwind operator functions on an embedded array. Let’s have a look at the “vehicleitems” collection.

db.vehicleitems.find().pretty()

Result:

In the next section, the $unwind operation is performed on the above documents using the “items” embedded arrays.

db.vehicleitems.aggregate({$unwind: "$items"}).pretty()

Result:

As you can see from the output documents, each item in all the “items” embedded arrays are deconstructed as individual items. You can further deconstruct the resulting data set using the “type” array, which we do in the next example.

Deconstruction syntax:

{$unwind: "$items"},{$unwind: "$items.type"}

Complete syntax:

db.vehicleitems.aggregate([{$unwind: "$items"},{$unwind: "$items.type"},{$project: { _id: 0}}])

Use the projection operator to remove the “objectId” field for a cleaner output.

Result:

That’s the end of this MongoDB $unwind tutorial.

Related reading

Free e-book: The Beginner’s Guide to MongoDB

MongoDB is the most popular NoSQL database today and with good reason. This e-book is a general overview of MongoDB, providing a basic understanding of the database.


These postings are my own and do not necessarily represent BMC's position, strategies, or opinion.

See an error or have a suggestion? Please let us know by emailing blogs@bmc.com.

BMC Brings the A-Game

BMC works with 86% of the Forbes Global 50 and customers and partners around the world to create their future. With our history of innovation, industry-leading automation, operations, and service management solutions, combined with unmatched flexibility, we help organizations free up time and space to become an Autonomous Digital Enterprise that conquers the opportunities ahead.
Learn more about BMC ›

About the author

Shanika Wickramasinghe

Shanika Wickramasinghe is a software engineer by profession and a graduate in Information Technology. Her specialties are Web and Mobile Development. Shanika considers writing the best medium to learn and share her knowledge. She is passionate about everything she does, loves to travel, and enjoys nature whenever she takes a break from her busy work schedule. You can connect with her on LinkedIn.