次のコードを使用して、既存のMongoDBコレクションにいくつかの挿入を実行しようとしています
db.dados_meteo.aggregate( [
{ $match : { "POM" : "AguiardaBeira" } },
{ $project : {
_id : { $concat: [
"0001:",
{ $substr: [ "$DTM", 0, 4 ] },
{ $substr: [ "$DTM", 5, 2 ] },
{ $substr: [ "$DTM", 8, 2 ] },
{ $substr: [ "$DTM", 11, 2 ] },
{ $substr: [ "$DTM", 14, 2 ] },
{ $substr: [ "$DTM", 17, 2 ] }
] },
"RNF" : 1, "WET":1,"HMD":1,"TMP":1 } },
{ $out : "dados_meteo_reloaded" }
] )
しかし、$ matchパラメーターを変更して新しい集計を行うたびに、Mongo DBは以前のドキュメントを削除し、新しい結果を挿入します。
私たちを手伝ってくれますか?
簡単な答えは「できません」です。
$ out操作で指定されたコレクションがすでに存在する場合、集計が完了すると、$ outステージは、既存のコレクションを新しい結果コレクションにアトミックに置き換えます。 $ out操作は、前のコレクションに存在していたインデックスを変更しません。集計が失敗した場合、$ out操作は既存のコレクションに変更を加えません。
回避策として、_$out
_で指定されたコレクションドキュメントを、いくつかの方法のいずれかで、集約の直後に「永続的な」コレクションにコピーできます(ただし、理想的ではありません)。
db.out.find().forEach(function(doc) {db.target.insert(doc)})
Mongo 4.2
を開始すると、新しい $merge
集計演算子($out
と同様)によりマージが可能になります指定されたコレクションへの集約パイプラインの結果:
この入力が与えられた場合:
db.source.insert([
{ "_id": "id_1", "a": 34 },
{ "_id": "id_3", "a": 38 },
{ "_id": "id_4", "a": 54 }
])
db.target.insert([
{ "_id": "id_1", "a": 12 },
{ "_id": "id_2", "a": 54 }
])
$merge
集約ステージは次のように使用できます。
db.source.aggregate([
// { $whatever aggregation stage, for this example, we just keep records as is }
{ $merge: { into: "target" } }
])
生産する:
// > db.target.find()
{ "_id" : "id_1", "a" : 34 }
{ "_id" : "id_2", "a" : 54 }
{ "_id" : "id_3", "a" : 38 }
{ "_id" : "id_4", "a" : 54 }
$merge
演算子には 多くのオプション が付属しており、既存のレコードと競合する挿入されたレコードをマージする方法を指定することに注意してください。
この場合(デフォルトのオプションを使用)、これは次のとおりです。
ターゲットコレクションの既存のドキュメントを保持します(これは{ "_id": "id_2", "a": 54 }
の場合です)
ドキュメントがまだ存在しない場合は、集約パイプラインの出力からターゲットコレクションにドキュメントを挿入します(_id
に基づく-これは{ "_id" : "id_3", "a" : 38 }
の場合です)
集約パイプラインがターゲットコレクションに存在するドキュメントを生成するときに、ターゲットコレクションのレコードを置き換えます(_id
に基づく-これは{ "_id": "id_1", "a": 12 }
が{ "_id" : "id_1", "a" : 34 }
に置き換えられた場合です)
これはこれまでで最も美しいものではありませんが、別の代替構文として(後処理のアーカイブ/追加操作から)...
db.targetCollection.insertMany(db.runCommand(
{
aggregate: "sourceCollection",
pipeline:
[
{ $skip: 0 },
{ $limit: 5 },
{
$project:
{
myObject: "$$ROOT",
processedDate: { $add: [new ISODate(), 0] }
}
}
]
}).result)
これがforEachバリアントとどのように重なるかはわかりませんが、より直感的に読むことができます。