I have a collection that looks like this
{ name: 'ABC', metadata.tables: [ { name: 'table1' }] }
Basically I want to query within the metadata.tables array to look for an elemMatch on the name of the table. I can do that using the aggregation pipeline by first unwinding the metadata.tables array and then doing the $match on table name. This works fine but now the metadata.tables becomes an object instead of an array. This is how the query looks like
db.source.aggregate([
{ "$unwind": "$metadata.tables" },
{ $match: { "metadata.tables.name": "table 1" } }
])
The returned document looks like this
{
"_id": "......",
"metadata": {
"tables": {
}
}
}
Notice the tables are now an object instead of an array. I understand why unwind changes it to an object but how can I revert it back to an array with a single element in it (the matching table).
Thanks
Just Perform a $group with a $push:
db.source.aggregate([
{ "$unwind": "$metadata.tables" },
{ "$match": { "metadata.tables.name": "table 1" } },
{ "$group": {
"_id": "$_id",
"name": { "$first": "$name" },
"tables": { "$push": "$metadata.tables" }
}},
{ "$project": {
"name": 1,
"metadata": {
"tables": "$tables"
}
}}
])
And optionally $project since aggregation accumulators cannot use an embedded field for output and you would need to rename much like as is shown.
Optionally you could use $map if you knew you only had or just wanted a single element out of each "unwound" document:
db.source.aggregate([
{ "$unwind": "$metadata.tables" },
{ "$match": { "metadata.tables.name": "table 1" } },
{ "$project": {
"name": 1,
"metadata": {
"tables": {
"$map": {
"input": ["A"],
"as": "el",
"in": "$metdata.tables"
}
}
}
}}
])
Which would essentially substitute the single element array provided to "input" with the value of the field.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With