web-dev-qa-db-ja.com

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

MongoDBでデータのバージョン管理をどのように実装するのか、考えを共有してください。 (私は Cassandraに関する同様の質問 を尋ねました。そのためにDBの方が良いと思う考えがあれば共有してください)

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

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

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

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

     {
     '_id': 'new id'、
     'user':user_id、
     'timestamp':timestamp、
     'address_book_id' : 'アドレス帳レコードのID' 
     'old_record':{'first_name': 'Jon'、 'last_name': 'Doe' ...} 
    } 
    

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

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

278
Piotr Czapla

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

  1. 違いますか?
  2. 全レコードのコピー?

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

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

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

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

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

更新:2015-10

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

141
Gates VP

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

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

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

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

30
Marian

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

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

dataにはallバージョンが含まれます。 data配列はorderedであり、新しいバージョンは配列の最後まで$Pushedのみを取得します。 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が必要なので、次のバージョンのvidnextVID = oldVID + 1を簡単に取得できます。

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

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

特定のバージョンを削除:

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

それでおしまい!

(ドキュメントごとに16MBの制限を覚えておいてください)

19
Benjamin M

すぐに使えるソリューションを探しているなら-

Mongoidにはシンプルなバージョン管理機能が組み込まれています

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

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

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

12
s01ipsist

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

{
  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

9
Daniel Watrous

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

mongoose-patch-history

3
bmw15

もう1つのオプションは、 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.
2
Muhammad Reda

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

nicklozon/meteor-collection-revisions

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

1
helcode