Подтвердить что ты не робот

Как сгладить субдокумент на корневом уровне в MongoDB?

Например, если у меня есть такой документ,

{
  a: 1,
  subdoc: {
          b: 2,
          c: 3
          }
}

Как я могу преобразовать его в такой формат? (без использования project)

{
  a: 1,
  b: 2,
  c: 3
}
4b9b3361

Ответ 1

Вы можете использовать проект 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
    }

Ответ 2

Вы можете использовать $replaceRoot со $addFields следующим образом:

db.collection.aggregate([
    { "$addFields": { "subdoc.a": "$a" } },
    { "$replaceRoot": { "newRoot": "$subdoc" }  }
])

Ответ 3

Лучший способ - использовать $replaceRoot и $mergeObjects

let pipeline = [
    {
        "$replaceRoot":{
            "newRoot":{
                "$mergeObjects":[
                    {
                        "a":"$a"
                    },
                    "$subdoc"
                ]
            }
        }
    }
]
db.collection.aggregate(pipeline)

Ответ 4

Вы можете сделать это с помощью $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".

Ответ 5

Я предполагаю, что самый простой способ - изменить результат после его возвращения, используя 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);

Ответ 6

Начиная с 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 }