たとえば、このようなドキュメントがある場合
{
a: 1,
subdoc: {
b: 2,
c: 3
}
}
どうすればこのような形式に変換できますか? (project
を使用せずに)
{
a: 1,
b: 2,
c: 3
}
使用できます 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
}
使用できます$replaceRoot
with a$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)
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
集計演算子を使用して、@ 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 }
これは、 _$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
_ の安全な使用法を採用しています実際にそこにあります。