MongoDB Aggregation Example: Extracting a specific field of an array element with matching condition

Changhun Lee
Jul 22, 2017 · 2 min read

At the first glance, MongoDB query seemed simpler and less powerful compared to SQL. (And that’s probably because I stopped reading the document after query operators section, and do whatever I had to do on the code where I handled the query result.) However as I dig deeper into it, I realized that it’s been holding all the power of matching, projection, aggregation and manipulation right in front of me.

Here’s a simple example to that.
Let’s assume that we got collection android with following structure,

{ 
"_id" : ObjectId("596b38fb28564de63a3aa884"),
"language" : "Macedoian",
"lastModified" : "2017-07-16 18:59:23",
"items" : [
{
"platform" : "android",
"id" : "theme",
"type" : "single",
"description" : "",
"image" : "",
"base" : "Theme",
"list" : false,
"target" : "тема"
},
{
"platform" : "android",
"id" : "alarm_turn_off_mode_title",
"type" : "single",
"description" : "",
"image" : "general_settings.png",
"base" : "Alarm off method",
"list" : false,
"target" : ""
}
]
}
{
"_id" : ObjectId("596b38ff28564de63a3aa89d"),
"language" : "Bosnian (Bosnia and Herzegovina)",
"lastModified" : "2017-07-16 18:59:27",
"items" : [
{
"platform" : "android",
"id" : "theme",
"type" : "single",
"description" : "",
"image" : "",
"base" : "Theme",
"list" : false,
"target" : "tema"
},
{
"platform" : "android",
"id" : "alarm_turn_off_mode_title",
"type" : "single",
"description" : "",
"image" : "general_settings.png",
"base" : "Alarm off method",
"list" : false,
"target" : ""
}
]
}

Here we’d like to extract target field of an item in items array with id of “theme” for each language. Assuming that there’s only one item with specific id in each language’s items, one target for one language is expected.
In the end, the result should look something like this.

{
"language": "aaa",
"target": "bbb",
}
{
"language": "ccc",
"target": "ddd"
}

There could be several ways to do that. You can ‘query and project’, ‘project only’ or do ‘aggregation’.
Using query and projection is rather easier but doesn’t deliver the result in an exact form we want. (Of course you can post-process the query result in your own code)
Using aggregation is a bit more complicated but we can get the result practically in any form we want it to be.

Following aggregation pipeline does exactly what we want. (This is just a quick example. There could be more complete, efficient ways to do the same.)

db.android.aggregate([
{
language: 1,
items: {
$filter: {
input: "$items",
as: "item",
cond: { $eq: [ "$$item.id", "theme"]}
}
}
},
{
language: 1,
target: {
$arrayElemAt: [ "$items.target", 0 ]
}
}
])

The result would be,

{ 
"_id" : ObjectId("596b38fb28564de63a3aa884"),
"language" : "Macedoian",
"target" : "тема"
}
{
"_id" : ObjectId("596b38ff28564de63a3aa89d"),
"language" : "Bosnian (Bosnia and Herzegovina)",
"target" : "tema"
}

TechUniverse

All about tech

Changhun Lee

Written by

TechUniverse

All about tech

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade