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


298

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

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

  • まれに使用されます
  • 一度に使用して「タイムマシン」形式で表示します
  • 1つのレコードに数百よりも多くのバージョンはありません。履歴に有効期限はありません。

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

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

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

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

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


1
質問が回答されてからこれが変更されたかどうかを知りたいですか?oplogについてはあまり詳しくありませんが、当時はこの程度でしたが、違いはありますか?
ランディL 14

私のアプローチは、すべてのデータを時系列として考えることです。

回答:


152

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

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


2
そのような履歴ドキュメント(変更オブジェクト)が時間とともに大きくなり、更新が非効率になることを心配しませんか?または、MongoDBが処理するドキュメントは簡単に増加しますか?
Piotr Czapla 2010年

5
編集を見てください。への追加changesは非常に簡単です。db.hist.update({_id: ID}, {$set { changes.12345 : CHANGES } }, true)これにより、必要なデータのみを変更するアップサートが実行されます。Mongoは、この種の変更を処理するための「バッファスペース」を備えたドキュメントを作成します。また、コレクション内のドキュメントがどのように変更されるかを監視し、各コレクションのバッファサイズを変更します。したがって、MongoDBはまさにこのタイプの変更(新しいプロパティの追加/配列へのプッシュ)のために設計されています。
Gates VP、

2
私はいくつかのテストを行ったが、実際にスペース予約はかなりうまく機能している。レコードがデータファイルの最後に再割り当てされたときに、パフォーマンスの低下を検出できませんでした。
Piotr Czapla 2010年

4
github.com/mirek/node-rus-diffを使用して、履歴の(MongoDB互換)差分を生成できます。
Mirek Rusin 2014年

1
JSONパッチRFCは difffsを表現する方法を提供します。それは持っているいくつかの言語での実装を
ジェローム2015年

31

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

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

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

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


5
実際にどのように使用しますか?
ハディー

6
このプロジェクトの実際の使用方法に関するドキュメントはありません。なんとなくモンゴと共生しているものでしょうか?それはJavaライブラリですか?それは単に問題についての考え方なのでしょうか?アイデアもヒントも与えられていません。
ftrotter 2013

1
これは実際のJavaアプリで、relavantコードはここに住ん:github.com/thiloplanz/v7files/blob/master/src/main/java/v7db/...
ftrotter

20

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

{
    _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

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

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

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

それでおしまい!

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


mmapv1ストレージでは、新しいバージョンがデータに追加されるたびに、ドキュメントが移動される可能性があります。
raok1997 2016年

はい、そうです。しかし、たまに新しいバージョンを追加するだけの場合、これは無視できるはずです。
Benjamin M


9

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

{
  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


素晴らしいもの:)
ジョナサン


4

別のオプションは、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.

1

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

nicklozon / meteor-collection-revisions

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.