I'm looking for a way to search a Mongo object for a specific key, and return its value and path if found.
The questions I've seen related to this use dot notation and $exists, since they know the structure of the object. In this case, however, the target field can sometimes be nested three levels deep and sometimes just one level, and I do not know the path to it or its parent key.
CodePudding user response:
Check my mongoplayground below, it can be used up to three level of array. If you want more level, just copy some of code and you can make it.
data
[
{
_id: 1,
"key": [
{
"key2": [
{
"key3": [
{}
]
}
]
}
]
},
{
_id: 2,
"key4": 2
}
]
aggregate
db.collection.aggregate([
{
$set: { n1: { $objectToArray: "$$ROOT" } }
},
{
$unwind: {
path: "$n1",
preserveNullAndEmptyArrays: true
}
},
{
$unwind: {
path: "$n1.v",
preserveNullAndEmptyArrays: true
}
},
{
$set: {
key_array: [ "$n1.k" ],
n2: {
$cond: {
if: { $eq: [ { $type: "$n1.v" }, "object" ] },
then: { $objectToArray: "$n1.v" },
else: null
}
}
}
},
{
$unwind: {
path: "$n2",
preserveNullAndEmptyArrays: true
}
},
{
$unwind: {
path: "$n2.v",
preserveNullAndEmptyArrays: true
}
},
{
$set: {
key_array: {
$concatArrays: [ "$key_array", [ "$n2.k" ] ]
},
n3: {
$cond: {
if: { $eq: [ { $type: "$n2.v" }, "object" ] },
then: { $objectToArray: "$n2.v" },
else: null
}
}
}
},
{
$unwind: {
path: "$n3",
preserveNullAndEmptyArrays: true
}
},
{
$unwind: {
path: "$n3.v",
preserveNullAndEmptyArrays: true
}
},
{
$set: {
key_array: {
$concatArrays: [ "$key_array", [ "$n3.k" ] ]
}
}
},
{
$group: {
_id: "$_id",
key_array: { $addToSet: "$key_array" }
}
},
{
$set: {
key_array: {
$reduce: {
input: "$key_array",
initialValue: [],
in: { $concatArrays: [ "$$value", "$$this" ] }
}
}
}
},
{
$unwind: "$key_array"
},
{
$match: { key_array: { $ne: null } }
},
{
$group: {
_id: "$_id",
key_array: { $addToSet: "$key_array" }
}
}
])
result
[
{
"_id": 1,
"key_array": [
"key",
"key3",
"_id",
"key2"
]
},
{
"_id": 2,
"key_array": [
"_id",
"key4"
]
}
]