I have following data in my collection:
[
{
_id: "2313123123",
metadata: {
path: "...",
value: "...",
name: "..."
}
},
{
_id: "2313123123",
metadata: {
path: "...",
name: "...",
origin: "...",
}
},
{
_id: "2313123123",
metadata: {
path: "...",
source: "..."
}
},
]
I want to retrieve all distinct key names of the field metadata from my documents.
I want to retrieve ["path", "value", "name", "origin", "source"].
How can I query for this? Is this possible with the distinct method or do I need to use aggregate?
CodePudding user response:
You'll have to use an aggregate for this, sadly due to the nature of your needs this is going to be a very "expensive" pipeline to execute. There is no way to avoid iterating over the entire collection and adding the unique keys to the array.
We're going to use $objectToArray to turn metadata into an array, then $unwind it and finally using $group we could save all the unique values.
db.collection.aggregate([
{
$project: {
keys: {
$map: {
input: {
"$objectToArray": "$metadata"
},
in: "$$this.k"
}
}
}
},
{
$unwind: "$keys"
},
{
$group: {
_id: null,
keys: {
"$addToSet": "$keys"
}
}
}
])
CodePudding user response:
db.collection.aggregate([
{
$addFields: {
metadata: {
$objectToArray: "$metadata"
}
}
},
{
$unwind: "$metadata"
},
{
$group: {
_id: "distinct",
dist: {
$addToSet: "$metadata.k"
}
}
}
])
explained:
- Convert the metadata object to metadata array having the keys as values in k key.
- Unwind the metadata array of k keys & v values
- group with addToSet to extract only the distinct k values in the final result.
helpfull javascript onliner from mongo shell option:
db.collection.find({},{metadata:1,_id:0}).forEach( function(doc) { for (key in doc.metadata) s.push(key); } );uni = Array.from(new Set(s));printjson(uni);
["path","name","origin","source","value"]
