🚩Unwind
Array deconstruction
The $unwind operator is used to deconstruct array fields. How deconstruction works ❓ For each array element a new document is produced having that element in the position of the field array. This means that applying the unwind operator on a single document's array field which contains 10 elements, produces 10 different documents having one of the array elements instead of the array field. It is possible to define if a new document will produced in case a document either doesn't contain the array field or it is empty.
{
"_id" : ObjectId("5e9afcd20f86e454c4518d8d"),
"name" : "Margarett Lind",
"age" : 59,
"activities" : [
"Golf",
"Photography",
"Hacking"
]
}// $unwind on activities
db.trips.aggregate()
.unwind("$activities")
// for each activity produces one document
/* 1 */
{
"_id" : ObjectId("5e9afcd20f86e454c4518d8d"),
"name" : "Margarett Lind",
"age" : 59,
"activities" : "Golf"
},
/* 2 */
{
"_id" : ObjectId("5e9afcd20f86e454c4518d8d"),
"name" : "Margarett Lind",
"age" : 59,
"activities" : "Photography"
},
/* 3 */
{
"_id" : ObjectId("5e9afcd20f86e454c4518d8d"),
"name" : "Margarett Lind",
"age" : 59,
"activities" : "Hacking"
}The following sample finds the distinct activities grouped by age for Traveler documents.
var travelersQueryableCollection = tripsDatabase
.GetCollection<Traveler>(Constants.TravelersCollection)
.AsQueryable();
var linqQuery = travelersQueryableCollection
.SelectMany(t => t.Activities, (t, a) => new
{
age = t.Age,
activity = a
})
.GroupBy(q => q.age)
.Select(g => new { age = g.Key, activities =
g.Select(a => a.activity).Distinct() })
.OrderBy(r => r.age);
var linqQueryResults = await linqQuery.ToListAsync();db.travelers.aggregate([
{
"$unwind":"$activities"
},
{
"$project":{
"age":"$age",
"activity":"$activities",
"_id":0
}
},
{
"$group":{
"_id":"$age",
"__agg0":{
"$addToSet":"$activity"
}
}
},
{
"$project":{
"age":"$_id",
"activities":"$__agg0",
"_id":0
}
},
{
"$sort":{
"age":1
}
}
])// sample results
/* 1 */
{
"age" : 22,
"activities" : [
"Photography",
"Road Touring"
]
},
/* 2 */
{
"age" : 25,
"activities" : [
"Photography",
"Blogging",
"Baking",
"Collecting",
"Hacking"
]
},
/* 3 */
{
"age" : 30,
"activities" : [
"Road Touring",
"Climbing"
]
},
/* 4 */
{
"age" : 34,
"activities" : [
"Photography"
]
}public class Traveler
{
[BsonId]
public ObjectId Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public List<string> Activities { get; set; }
public List<VisitedCountry> VisitedCountries { get; set; }
}LINQ query explanation
SelectManyon Activities creates the $unwind stagenew { }creates the $project stageGroupBygroups documents by age fieldSelectcreates another $project stage whereDistinctensures activities will not contain duplicate values per group - it does that by using $addToSet operator in the $group stage rather than a $push
Last updated