2017-01-09 26 views
4

MongoDBを使用して時系列を処理しようとしています。コミュニティによって採用されている共通の解決策は、サブ文書を使用して異なるレベルの細かさで情報を格納することです( Schema Design for Time Series Data in MongoDB参照)。MongoDBコレクションの更新:デフォルト値で文書を初期化する

{ 
    timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"), 
    type: “memory_used”, 
    values: [ 
    999999, // 1 second 
    … 
    1000000, // nth second 
    1500000, // n+1th second 
    … 
    2000000 // 60th 
    ] 
} 

文書を分情報によって索引付けされ、各第二のためのより詳細な情報を格納するサブ文書が含ま:

は、例えば、以下の文書を見てみましょう。

これまでのところとても良いです。この種のアプローチは、正しく動作するために最適化を必要とする:

Another optimization [..] is preallocating all documents for the upcoming time period; This never causes an existing document to grow or be moved on disk.

1はupdate方法に$setOnInsertプロパティを使用することができます上記の最適化を実現するために。

db.getCollection('aCollection').update(
    { 
     timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"), 
     type: “memory_used” 
    }, 
    { 
     $setOnInsert: { values: {'0': 0, '1': 0, '2': 0}}, 
     $inc: {"values.30": 1} 
    }, 
    { upsert: true } 
) 

同じアップデートを2つの異なる操作で使用することはできません。この問題は、このissueに追跡さ

Cannot update 'values' and 'values.30' at the same time 

:上記更新istruction、次のエラーが発生します。

私の質問です:回避策はありますか?私はインデックスフィールドフィールドtypeの先験的(上記の例では、値の値を知ることができないので、私は、空の文書を事前に割り当て任意のバッチを使用することはできません。

感謝の接頭辞事前に。

答えて

4

私と私の同僚は、回避策を見つけました。私たちは、3段階の初期化それを呼び出すことができます。

のMongoDBは、単一の文書に対する操作のアトミック性を保証する。この事実で、私たちが動作することができ、心に覚えておいてください以下のようにしてください:

  1. 指定した時刻のチャンクでカウンタを正しくインクリメントして、ドキュメントを更新してみてください。 upsertはしないでください。ちょうど昔ながらのアップデート操作です。 update文を実行すると、書き込まれたドキュメントの数が返されることに注意してください。書かれた書類の数が0より大きい場合、完了です。
  2. 更新プログラムによって書き込まれたドキュメントの数がゼロの場合、更新する相対ドキュメントがまだコレクションに存在しないことを意味します。指定したタグのドキュメント全体を挿入してください。すべてのカウンター(項目値)をゼロにする。また、insert文を実行すると、書かれた書類の数が返されます。ゼロを返すか例外をスローした場合、他のプロセスがすでに同じタグのドキュメントを挿入していたことに気付かないでください。
  3. 上記の同じアップデートを再度実行してください。

コードは、次のコードスニペットのようになります。前提条件が成立する場合

// Firt of all, try the update 
var result = db.test.update(
    {timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"), type: “memory_used”}, 
    {$inc: {"values.39": 1}}, 
    {upsert: false} 
); 
// If the update do not succeed, then try to insert the document 
if (result.nModified === 0) { 
    try { 
    db.test.insert(/* Put here the whole document */); 
    } catch (err) { 
    console.log(err); 
    } 
    // Here we are sure that the document exists. 
    // Retry to execute the update statement 
    db.test.update(/* Same update as above */); 
} 

上記の手順が動作します:_id値は、文書内の他の分野から派生する必要があります。この例では、_idの値は'2013-10-10T23:06:00.000Z-memory_usedとなります。この技法を使用する場合のみ、ポイント2の挿入が正しく失敗します。

+1

なぜ挿入に失敗しますか?タイプとタイムスタンプにユニークなインデックスがありますか? –

+0

あなたが正しいです、私はこの点を挿入することを忘れています。 '_id'は文書の他のフィールドから派生しなければなりません。 –

関連する問題