MongoDBでデータバージョンを実装する方法
-
10-10-2019 - |
質問
MongoDBでデータバージョンをどのように実装するかを考えてみてください。 (私は尋ねました カサンドラに関する同様の質問. 。 DBが優れている考えがある場合は、共有してください)
簡単なアドレス帳でレコードをバージョンする必要があると仮定します。 (アドレス帳のレコードは、フラットJSONオブジェクトとして保存されます)。私は歴史を期待しています:
- まれに使用されます
- 「タイムマシン」ファッションでそれを提示するために一度に使用されます
- 単一のレコードから数百以上のバージョンはありません。歴史は失効しません。
次のアプローチを検討しています。
記録の履歴またはレコードの変更を保存するための新しいオブジェクトコレクションを作成します。アドレス帳のエントリを参照して、バージョンごとに1つのオブジェクトを保存します。そのような記録は次のように見えます:
{ '_id': 'new id', 'user': user_id, 'timestamp': timestamp, 'address_book_id': 'id of the address book record' 'old_record': {'first_name': 'Jon', 'last_name':'Doe' ...} }
このアプローチは、ドキュメントごとに一連のバージョンを保存するために変更できます。しかし、これは利点がないほど遅いアプローチのようです。
アドレス帳エントリに添付されたシリアル化(JSON)オブジェクトとしてバージョンを保存します。そのようなオブジェクトをmongodbドキュメントに添付する方法がわかりません。おそらく一連の文字列として。 (CouchDBを使用した単純なドキュメントバージョンの後にモデル化されています)
解決
これに飛び込むときの最初の大きな質問は 「チェンジセットをどのように保存したいですか」?
- diffs?
- レコード全体のコピー?
私の個人的なアプローチは、ディフを保存することです。これらのdiffの表示は本当に特別なアクションであるため、Diffsを別の「歴史」コレクションに入れます。
別のコレクションを使用してメモリスペースを保存します。通常、あなたは簡単なクエリのための完全な履歴を望んでいません。したがって、オブジェクトから履歴を守ることにより、そのデータが照会されたときに、一般的にアクセスされるメモリからそれを締め出すこともできます。
私の人生を楽にするために、私は歴史文書に時間刻印されたディフの辞書を含むようにします。このようなもの:
{
_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を処理するための仕様. 。これは、DIF /変更を保存するためのより堅牢な方法のようです。
他のヒント
他の返信では扱われていないいくつかの側面に対処する「Vermongo」と呼ばれるバージョンスキームがあります。
これらの問題の1つは同時更新です。もう1つはドキュメントを削除しています。
Vermongoは、Shadow Collectionに完全なドキュメントコピーを保存します。一部のユースケースでは、これは頭上が大きすぎる可能性がありますが、多くのことを簡素化すると思います。
現在のバージョンとすべての古いバージョンに単一のドキュメントを使用した別のソリューションは次のとおりです。
{
_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を覚えておいてください)
すぐにロールできるソリューションをお探しの場合 -
Mongoidは単純なバージョンに組み込まれています
http://mongoid.org/en/mongoid/docs/extras.html#versioning
Mongoid-Historyは、監査、元に戻し、やり直しを伴う非常に複雑なソリューションを提供するRubyプラグインです
私は、データの公開、ドラフト、および履歴バージョンに対応するこのソリューションを使用しました。
{
published: {},
draft: {},
history: {
"1" : {
metadata: <value>,
document: {}
},
...
}
}
ここでモデルについてさらに説明します: http://software.danielwatrous.com/representing-revision-data-in-mongodb/
このようなものを実装できる人のために ジャワ, 、ここに例があります:
http://software.danielwatrous.com/using-java-to-work-with-versioned-data/
あなたが望むなら、あなたがフォークできるすべてのコードを含める
Mongooseを使用している場合、次のプラグインが有用な実装であることがわかりました。 JSONパッチ フォーマット
別のオプションは使用することです マングースヒストリー プラグイン。
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を使用することです(ここ)