web-dev-qa-db-ja.com

Mongo DB集計結果を既存のコレクションに追加するにはどうすればよいですか?

次のコードを使用して、既存の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は以前のドキュメントを削除し、新しい結果を挿入します。

私たちを手伝ってくれますか?

9
Hugo

簡単な答えは「できません」です。

$ out操作で指定されたコレクションがすでに存在する場合、集計が完了すると、$ outステージは、既存のコレクションを新しい結果コレクションにアトミックに置き換えます。 $ out操作は、前のコレクションに存在していたインデックスを変更しません。集計が失敗した場合、$ out操作は既存のコレクションに変更を加えません。

回避策として、_$out_で指定されたコレクションドキュメントを、いくつかの方法のいずれかで、集約の直後に「永続的な」コレクションにコピーできます(ただし、理想的ではありません)。

  • copyTo() が最も簡単です、警告に注意してください。小さな結果のために他を使用しないでください。
  • JSを使用する:db.out.find().forEach(function(doc) {db.target.insert(doc)})
  • Mongoexport/mongoimportを使用します
9
Ori Dar

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 }に置き換えられた場合です)

6
Xavier Guihot

これはこれまでで最も美しいものではありませんが、別の代替構文として(後処理のアーカイブ/追加操作から)...

db.targetCollection.insertMany(db.runCommand(
{
    aggregate: "sourceCollection",
    pipeline: 
    [
        { $skip: 0 },
        { $limit: 5 },
        { 
            $project:
            {
                myObject: "$$ROOT",
                processedDate: { $add: [new ISODate(), 0] }
            }
        }
    ]
}).result)

これがforEachバリアントとどのように重なるかはわかりませんが、より直感的に読むことができます。

1
Jesse MacNett