web-dev-qa-db-ja.com

MongoDBでサブドキュメントをルートレベルにフラット化する方法は?

たとえば、このようなドキュメントがある場合

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

どうすればこのような形式に変換できますか? projectを使用せずに)

{
  a: 1,
  b: 2,
  c: 3
}
26
syg

使用できます MongoDBプロジェクション、つまり$project集約フレームワークパイプライン演算子 も同様です。(推奨される方法)。 projectを使用したくない場合は、これを確認してください link

db.collection.aggregation([{$ project {。。}}]);

以下はあなたのケースの例です:

db.collectionName.aggregate
([
    { $project: { a: 1, 'b': '$subdoc.b', 'c': '$subdoc.c'} }
]);

期待どおりの出力が得られます。

    {
        "a" : 1,
        "b" : 2,
        "c" : 3
    }
25
Amol M Kulkarni

使用できます$replaceRootwith a$addFieldsステージは次のとおりです。

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

最善の方法は $replaceRoot および $mergeObjects

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

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);
0
ariel

Mongo 4.2から、 $replaceWith 集計演算子を使用して、@ chridamで言及されている$replaceRootの構文上の砂糖として、ドキュメントを別のドキュメント(この場合はサブドキュメント)に置き換えることができます。

したがって、最初にサブドキュメント内にルートフィールドを含めて、 $set 演算子(Mongo 4.2のエイリアスとして$addFieldsでも導入)を使用し続け、次に$replaceWithを使用してドキュメント全体をサブドキュメントに置き換えることができます。 :

// { a: 1, subdoc: { b: 2, c: 3 } }
db.collection.aggregate([
  { $set: { "subdoc.a": "$a" } },
  { $replaceWith: "$subdoc" }
])
// { b: 2, c: 3, a: 1 }
0
Xavier Guihot

これは、 _$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" }
    );
})
_

また、「subdoc」キーがあるドキュメントを確実に選択するために、 _$exists_ の安全な使用法を採用しています実際にそこにあります。

0
Neil Lunn