Собирать различные имена полей на вложенном уровне с определенным условием
У меня есть постановка задачи, в которой мне нужны все имена полей на дочернем уровне "config.first.second", где поле включения имеет значение true хотя бы один раз. Вот моя коллекция предметов монго.
[ {
"_id" : ObjectId("560e97f4a78eb445cd2d75e5"),
"config" : {
"first" : {
"second" : {
"field1" : {
"include":"true"
},
"field3" : {
"include":"true"
},
"field9" : {
"include":"false"
},
"field6" : {
"include":"false"
}
}
}
},
"date_created" : "Fri Oct 02 14:43:00 UTC 2015",
"last_updated" : "Mon Apr 11 15:26:37 UTC 2016",
"id" : ObjectId("560e97f4a78eb445cd2d75e5")
},
{
"_id" : ObjectId("56154465a78e41c04692af20"),
"config" : {
"first" : {
"second" : {
"field1" : {
"include":"true"
},
"field3" : {
"include":"false"
},
"field7" : {
"include":"true"
}
}
}
},
"date_created" : "Wed Oct 07 16:12:21 UTC 2015",
"last_updated" : "Mon Apr 11 15:18:58 UTC 2016",
"id" : ObjectId("56154465a78e41c04692af20")
}
]
Используя вышеупомянутую коллекцию монго. Запрос должен вернуть результат
["field1","field3","field7"]
1 ответ
Решение
Вы можете запустить с mapReduce:
db.collection.mapReduce(
function() {
Object.keys(this.config.first.second)
.filter( k => this.config.first.second[k].include === "true" )
.forEach(k => emit(k,1) );
},
function() { },
{
"out": { "inline": 1 },
}
)['results'].map( d => d._id )
Если у вас есть MongoDB 3.4, то вы можете использовать .aggregate()
:
db.collection.aggregate([
{ "$project": {
"field": {
"$filter": {
"input": { "$objectToArray": "$config.first.second" },
"as": "f",
"cond": { "$eq": [ "$$f.v.include", "true" ] }
}
}
}},
{ "$unwind": "$field" },
{ "$group": { "_id": "$field.k" } }
]).toArray().map(d => d._id)
Возвращает:
[
"field1",
"field3",
"field7"
]