Например, если у меня есть такой документ,
{
a: 1,
subdoc: {
b: 2,
c: 3
}
}
Как я могу преобразовать его в такой формат? (без использования project
)
{
a: 1,
b: 2,
c: 3
}
Например, если у меня есть такой документ,
{
a: 1,
subdoc: {
b: 2,
c: 3
}
}
Как я могу преобразовать его в такой формат? (без использования project
)
{
a: 1,
b: 2,
c: 3
}
Вы можете использовать проект MongoDB i.e $project
операторов конвейерной структуры агрегации. (рекомендуется). Если вы не хотите использовать project
, проверьте эту ссылку
db.collection.aggregation([{$ project {.}}]);
Ниже приведен пример вашего случая:
db.collectionName.aggregate
([
{ $project: { a: 1, 'b': '$subdoc.b', 'c': '$subdoc.c'} }
]);
Дает вам результат, как вы ожидали.
{
"a" : 1,
"b" : 2,
"c" : 3
}
Вы можете использовать $replaceRoot
со $addFields
следующим образом:
db.collection.aggregate([
{ "$addFields": { "subdoc.a": "$a" } },
{ "$replaceRoot": { "newRoot": "$subdoc" } }
])
Лучший способ - использовать $replaceRoot
и $mergeObjects
let pipeline = [
{
"$replaceRoot":{
"newRoot":{
"$mergeObjects":[
{
"a":"$a"
},
"$subdoc"
]
}
}
}
]
db.collection.aggregate(pipeline)
Вы можете сделать это с помощью $set
и $unset
db.collection.update({},{ $set: { "b": 2, "c": 3 }, $unset: { "subdoc": 1 } })
Конечно, если в коллекции много документов, то, как и выше, вам нужно закодировать документы коллекции, чтобы получить значения. MongoDB не имеет возможности ссылаться на значение поля только в операции обновления:
db.collection.find({ "subdoc": {"$exists": 1 } }).forEach(function(doc) {
var setDoc = {};
for ( var k in doc.subdoc ) {
setDoc[k] = doc.subdoc[k];
}
db.collection.update(
{ "_id": doc._id },
{ "$set": setDoc, "$unset": "subdoc" }
);
})
Это также использует некоторое безопасное использование $exists
, чтобы убедиться, что вы выбираете документы, На самом деле ключ "subdoc".
Я предполагаю, что самый простой способ - изменить результат после его возвращения, используя map
.
collection.mapFunction = function(el) {
el.b = el.subdoc.b;
el.c = el.subdoc.c
delete(el.subdoc);
return el;
}
...
var result = await collection.aggregate(...).toArray();
result = result.map(collection.mapFunction);
Начиная с Mongo 4.2
, оператор агрегации $replaceWith
можно использовать для замены документа другим (в нашем случае вложенным документом) в качестве синтаксического сахара для $replaceRoot
упомянутого @chridam.
Таким образом, мы можем сначала включить в $addFields
корневое поле, чтобы продолжать использовать оператор $set
(также введенный в Mongo 4.2
в качестве псевдонима для $addFields
), а затем заменить весь документ на $addFields
используя $replaceWith
:
// { a: 1, subdoc: { b: 2, c: 3 } }
db.collection.aggregate([
{ $set: { "subdoc.a": "$a" } },
{ $replaceWith: "$subdoc" }
])
// { b: 2, c: 3, a: 1 }