MongoDBでデータのバージョン管理を実装する方法

2010-11-15 mongodb database-versioning

MongoDBでデータのバージョン管理をどのように実装するかについて、考えを共有できますか。 (私はCassandraについて同様の質問をしました。どのdbがより適しているかについての考えがある場合は共有してください)

単純なアドレス帳のレコードにバージョンを付ける必要があるとします。 (アドレス帳のレコードはフラットなjsonオブジェクトとして保存されます)。私はその歴史を期待しています:

  • まれに使用されます
  • 一度に「タイムマシン」形式で表示するために使用されます
  • 単一のレコードに数百を超えるバージョンはありません。 履歴に有効期限はありません。

私は以下のアプローチを検討しています:

  • 新しいオブジェクトコレクションを作成して、レコードの履歴またはレコードへの変更を保存します。アドレス帳エントリへの参照を使用して、バージョンごとに1つのオブジェクトを格納します。このようなレコードは次のようになります。

     { 
     '_id': '新しいID'、 
     「ユーザー」:user_id、 
     'timestamp':タイムスタンプ、 
     'address_book_id': 'アドレス帳レコードのID' 
     'old_record':{'first_name': 'Jon'、 'last_name': 'Doe' ...} 
     } 
    

    このアプローチは、ドキュメントごとにバージョンの配列を格納するように変更できます。しかし、これには利点がなく、遅いアプローチのようです。

  • バージョンをアドレス帳エントリに添付されたシリアル化(JSON)オブジェクトとして保存します。このようなオブジェクトをMongoDBドキュメントに添付する方法がわかりません。おそらく文字列の配列として。 ( CouchDBを使用したシンプルなドキュメントのバージョニングをモデルにしています

Answers

これに飛び込むときの最初の大きな質問は、 「どのようにしてチェンジセットを保存したいです。

  1. 差分?
  2. レコード全体のコピー?

私の個人的なアプローチは、差分を保存することです。これらの差分の表示は特別なアクションであるため、差分を別の「履歴」コレクションに入れます。

別のコレクションを使用して、メモリ領域を節約します。通常、単純なクエリの完全な履歴は必要ありません。したがって、オブジェクトから履歴を除外することで、そのデータがクエリされたときに、一般的にアクセスされるメモリから履歴を除外することもできます。

私の人生を楽にするために、私は履歴文書にタイムスタンプ付きの差分の辞書を含めます。このようなもの:

{
    _id : "id of address book record",
    changes : { 
                1234567 : { "city" : "Omaha", "state" : "Nebraska" },
                1234568 : { "city" : "Kansas City", "state" : "Missouri" }
               }
}

私の人生を本当に簡単にするために、私は自分のデータにアクセスするために使用するDataObjects(EntityWrapperなど)のこの部分を作成します。通常、これらのオブジェクトには何らかの形式の履歴があるため、 save()メソッドを簡単にオーバーライドして、この変更を同時に行うことができます。

更新:2015-10

JSON diffを処理するための仕様ができたようです。これは、差分/変更を保存するためのより堅牢な方法のようです。

すぐに使えるソリューションをお探しの場合-

Mongoidには単純なバージョン管理が組み込まれています

http://mongoid.org/en/mongoid/docs/extras.html#versioning

mongoid-historyはRubyプラグインであり、監査、元に戻す、およびやり直しを行う非常に複雑なソリューションを提供します

https://github.com/aq1018/mongoid-history

「Vermongo」と呼ばれるバージョン管理スキームがあり、他の返信では扱われていないいくつかの側面に対処しています。

これらの問題の1つは同時更新であり、もう1つはドキュメントの削除です。

Vermongoは、完全なドキュメントコピーをシャドウコレクションに格納します。一部のユースケースでは、これによりオーバーヘッドが大きくなりすぎる可能性がありますが、多くのことを単純化すると思います。

https://github.com/thiloplanz/v7files/wiki/Vermongo

私は、データの公開、ドラフト、および履歴バージョンに対応するこのソリューションに取り組みました。

{
  published: {},
  draft: {},
  history: {
    "1" : {
      metadata: <value>,
      document: {}
    },
    ...
  }
}

ここでモデルについてさらに説明します: http : //software.danielwatrous.com/representing-revision-data-in-mongodb/

Javaでこのようなものを実装する可能性のある人のために、ここに例があります:

http://software.danielwatrous.com/using-java-to-work-with-versioned-data/

必要に応じて、フォークできるすべてのコードを含めます

https://github.com/dwatrous/mongodb-revision-objects

現在のバージョンとすべての古いバージョンの単一のドキュメントを使用する別のソリューションを次に示します。

{
    _id: ObjectId("..."),
    data: [
        { vid: 1, content: "foo" },
        { vid: 2, content: "bar" }
    ]
}

dataすべてのバージョンが含まれます。 data配列は順序付けされており、新しいバージョンでは配列の最後にのみ$pushれます。 data.vidはバージョンIDであり、増分する番号です。

最新バージョンを取得します。

find(
    { "_id":ObjectId("...") },
    { "data":{ $slice:-1 } }
)

vid特定のバージョンを取得します。

find(
    { "_id":ObjectId("...") },
    { "data":{ $elemMatch:{ "vid":1 } } }
)

指定されたフィールドのみを返す:

find(
    { "_id":ObjectId("...") },
    { "data":{ $elemMatch:{ "vid":1 } }, "data.content":1 }
)

新しいバージョンを挿入:(および挿入/更新の同時実行を防止)

update(
    {
        "_id":ObjectId("..."),
        $and:[
            { "data.vid":{ $not:{ $gt:2 } } },
            { "data.vid":2 }
        ]
    },
    { $push:{ "data":{ "vid":3, "content":"baz" } } }
)

2は現在の最新バージョンのvidで、 3は挿入される新しいバージョンです。最新バージョンのvidが必要なため、次のバージョンのvid取得するのは簡単です: nextVID = oldVID + 1

$and条件は、 2が最新のvidであることを保証します。

この方法では一意のインデックスは必要ありませんが、アプリケーションロジックは挿入時にvidをインクリメントする必要があります。

特定のバージョンを削除します。

update(
    { "_id":ObjectId("...") },
    { $pull:{ "data":{ "vid":2 } } }
)

それでおしまい!

(ドキュメントあたりの制限は16MBです)

mongooseを使用している場合、次のプラグインがJSONパッチ形式の便利な実装であることがわかりました

マングースパッチの歴史

別のオプションは、 mongoose-historyプラグインを使用することです。

let mongoose = require('mongoose');
let mongooseHistory = require('mongoose-history');
let Schema = mongoose.Schema;

let MySchema = Post = new Schema({
    title: String,
    status: Boolean
});

MySchema.plugin(mongooseHistory);
// The plugin will automatically create a new collection with the schema name + "_history".
// In this case, collection with name "my_schema_history" will be created.

meteor / MongoDBプロジェクトに以下のパッケージを使用しましたが、うまく機能します。主な利点は、同じドキュメント内の配列内に履歴/リビジョンを保存することです。そのため、変更履歴にアクセスするための追加のパブリケーションやミドルウェアは必要ありません。 。限られた数の以前のバージョン(最後の10バージョンなど)をサポートでき、変更の連結もサポートします(そのため、特定の期間内に発生したすべての変更は1つのリビジョンでカバーされます)。

nicklozon / meteor-collection-revisions

別のサウンドオプションは、Meteor Vermongoを使用することです( ここ

Related