322

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

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

  • まれに使用されます
  • 「タイムマシン」のように一度に表示するために使用されます
  • 1 つのレコードに数百以上のバージョンが存在することはありません。履歴は失効しません。

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

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

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

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

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

4

8 に答える 8

163

これに飛び込むときの最初の大きな質問は、「変更セットをどのように保存したいですか? 」ということです。

  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 を処理するための仕様ができたようです。これは、差分/変更を保存するためのより堅牢な方法のようです。

于 2010-11-15T22:01:05.547 に答える
33

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

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

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

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

于 2012-10-27T09:00:14.163 に答える
28

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

{
    _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" } } }
)

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

状態は、それが最新のもの$andであることを保証します。2vid

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

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

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

それでおしまい!

(ドキュメントあたり 16MB の制限に注意してください)

于 2015-03-14T04:38:13.647 に答える
14

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

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

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

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

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

于 2012-08-11T00:23:12.970 に答える