Можно ли легко вернуть все поля поддокумента в виде полей в документе верхнего уровня, используя структуру агрегации?
У меня есть документ, подобный следующему, из которого я хочу вернуть подполя текущего поля верхнего уровня в качестве полей верхнего уровня в каждом документе массива результатов:
{
field1: {
subfield1: {},
subfield2: [],
subfield3: 44,
subfield5: xyz
},
field2: {
othercontent: {}
}
}
Я хочу, чтобы результаты моего запроса агрегации возвращали следующее (содержимое поля field1
как документа верхнего уровня):
{
subfield1: {},
subfield2: [],
subfield3: 44,
subfield5: xyz
}
Можно ли это сделать с помощью $project
и структуры агрегации, не определяя все подполя для возврата в качестве поля верхнего уровня?
Ответы
Ответ 1
Вы можете использовать $replaceRoot оператор агрегации с 3.4:
db.getCollection('sample').aggregate([
{
$replaceRoot: {newRoot: "$field1"}
}
])
Обеспечивает вывод как ожидается:
{
"subfield" : {},
"subfield2" : [],
"subfield3" : 44,
"subfield5" : "xyz"
}
Ответ 2
В целом трудно заставить MongoDB работать с двусмысленными или параметризованными ключами json. Я столкнулся с аналогичной проблемой, и лучшим решением было изменение схемы таким образом, чтобы члены поддокумента стали элементами массива.
Однако я думаю, что это приблизит вас к тому, что вы хотите (весь код должен запускаться непосредственно в оболочке Mongo). Предполагая, что у вас есть такие документы, как:
db.collection.insert({
"_id": "doc1",
"field1": {
"subfield1": {"key1": "value1"},
"subfield2": ["a", "b", "c"],
"subfield3": 1,
"subfield4": "a"
},
"field2": "other content"
})
db.collection.insert({
"_id": "doc2",
"field1": {
"subfield1": {"key2": "value2"},
"subfield2": [1, 2, 3],
"subfield3": 2,
"subfield4": "b"
},
"field2": "yet more content"
})
Затем вы можете запустить команду агрегации, которая продвигает содержимое field1
, игнорируя остальную часть документа:
db.collection.aggregate({
"$group":{
"_id": "$_id",
"value": {"$push": "$field1"}
}})
Это делает все ключи subfield*
в поля верхнего уровня объекта, и этот объект является единственным элементом в массиве. Это неуклюжий, но работоспособный:
"result" : [
{
"_id" : "doc2",
"value" : [
{
"subfield1" : {"key2" : "value2"},
"subfield2" : [1, 2, 3],
"subfield3" : 2,
"subfield4" : "b"
}
]
},
{
"_id" : "doc1",
"value" : [
{
"subfield1" : {"key1" : "value1"},
"subfield2" : ["a","b","c"],
"subfield3" : 1,
"subfield4" : "a"
}
]
}
],
"ok" : 1
Ответ 3
Начиная с Mongo 4.2
, оператор агрегации $replaceWith
можно использовать для замены документа другим (в нашем случае вложенным документом) в качестве синтаксического сахара для $replaceRoot
:
// { field1: { a: 1, b: 2, c: 3 }, field2: { d: 4, e: 5 } }
// { field1: { a: 6, b: 7 }, field2: { d: 8 } }
db.collection.aggregate({ $replaceWith: "$field1" })
// { a: 1, b: 2, c: 3 }
// { a: 6, b: 7 }