
アイデア
プロジェクトのアイデアは、MongoDBの代わりにクライアントコードを変更する代わりにInterSystemsCachéを使用できるように、ドキュメントの検索、保存、更新、削除のためのMongoDB APIの基本機能を実装することです。
やる気
おそらく、MongoDBインターフェースを使用し、InterSystemsCachéをデータウェアハウスとして使用すると、パフォーマンスをある程度向上させることができます。
まあ、なぜですか?! ¯\ _(ツ)_ /¯
制限事項
研究プロジェクトの枠組みの中で、いくつかの単純化が行われました。
-プリミティブデータ型のみが使用されます。
-null、boolean、number、string、array、object、ObjectId;
-クライアントコードは、MongoDBドライバーを介してMongoDBで動作します。
-クライアントコードはMongoDB Node.jsドライバーを使用します。
-クライアントコードは、MongoDB APIの基本機能のみを使用します。
-find 、 findOne-文書の検索。
- 保存 、 挿入 -ドキュメントの保存。
- 更新 -ドキュメントの更新。
- 削除 -文書の削除 。
- カウント -文書のカウント。
実装
その結果、タスクは次のサブタスクに分割されました。
-選択した基本機能のMongoDB Node.jsドライバーインターフェイスを再現します。
-InterSystemsCachéをデータウェアハウスとして使用して、このインターフェイスを実装します。
-Cachéでデータベース表現スキームを開発します。
-Cachéでコレクションのプレゼンテーションスキームを開発します。
-Cachéでドキュメント送信スキームを開発します。
-Node.jsを使用してCachéと対話するスキームを開発します。
-開発されたスキームを実装し、 少しテストします。 :)
実装の詳細
最初のサブタスクには特に困難はありませんでしたので、インターフェイス実装のサブタスクに直接進みます。
MongoDBは、データベースをコレクションの物理コンテナとして定義します 。 ドキュメントセットとしてのコレクション。 そして最後に、データセットとしてのドキュメント。 このドキュメントはJSONドキュメントに似ていますが、多数の有効なタイプ-BSONがあります。
InterSystemsCachéでは、すべてのデータはグローバルに保存されます 。 簡単に言えば、グローバルは階層データ構造と考えることができます。
このプロジェクトでは、すべてのデータが1つのグローバル- ^ MonCacheに保存されます。
したがって、データベース、コレクション、およびドキュメントを階層データ構造を使用して表すためのスキームを開発する必要があります。
Cachéのデータベース表示スキーム
MongoDBでは、1つのインスタンスに複数のデータベースが存在する可能性があります。つまり、互いに分離された複数のデータベースを保存できるプレゼンテーションスキームを開発する必要があります。 MongoDBはコレクションフリーデータベース(以下「空の」データベース)をサポートしていることに注意することも重要です。
私は問題を解決するための最も簡単で最も明白な方法を選びました。 データベースは、^ MonCacheグローバルの最初のレベルのノードで表されます。 さらに、「空の」データベースのサポートを実装するために、そのようなノードに値「」が割り当てられます。 問題は、これを行わずに子ノードを追加するだけで、すべての子ノードが削除されるとすぐに親ノードも削除されることです(グローバル機能)。
合計で、各データベースはCachéで次のように表示されます。
^MonCache(<db>) = ""
たとえば、データベースビュー「my_database」は次のようになります。
^MonCache("my_database") = ""
Cachéコレクションスキーム
MongoDBは、コレクションをデータベースアイテムとして定義します。 1つのデータベース内のすべてのコレクションには一意の名前があります。つまり、その名前を使用してコレクションを一意に識別できます。 この事実により、グローバルでコレクションを表す簡単な方法、つまり第2レベルのノードを使用する方法を見つけることができました。 次に、2つの小さな問題を解決する必要があります。 1つ目は、データベースと同様に、コレクションも空にできることです。 2番目は、コレクションがドキュメントのコレクションであることです。 そして、すべてのドキュメントは相互に分離する必要があります。 正直なところ、自動インクリメント値のようなものをコレクションノードの値として保存することは、私の心を決して越えませんでした。 すべてのドキュメントには独自の番号があります。 新しいドキュメントがコレクションに挿入されると、現在のカウンター値と同じ名前のノードが作成され、その後カウンター値が1増加します。
合計で、各コレクションはCachéで次のように表示されます。
^MonCache(<db>) = "" ^MonCache(<db>, <collection>) = 0
たとえば、データベース「my_database」のコレクション「my_collection」の表現は次のようになります。
^MonCache("my_database") = "" ^MonCache("my_database", "my_collection") = 0
Cachéのドキュメント送信スキーム
このプロジェクトのドキュメントは、追加のタイプであるObjectIdによって拡張されたJSONドキュメントです。 階層データ構造でドキュメントを提示するためのスキームを開発する必要がありました。 ここでいくつかの驚きが待っていました。 まず、Cachéはnullをサポートしていないため、Cachéでネイティブnullを使用する方法はありません。 2番目の興味深い点は、ブール値が定数0と1によって実装されることです。つまり、大まかに言うと、true-1、false-0です。最も予期される問題は、ObjectIdの格納方法を理解する必要があるということです。 一般的に、これらの問題はすべて、私にとっては単純な形のように思われたが、ほとんどの場合に成功裏に解決された。 次に、各データ型とその表示を調べます。
プレゼンテーションスキーム
より簡潔な記録のために、特別な表記- @を使用します。
^ MonCache(<db>、<collection>、<document id>、...)の代わりに書くだけです
@(...) 。
タイプ「null」のフィールドfがあるとします。
次の表現を定義します。
タイプ「boolean」(true)のフィールドfがあるとします。
次の表現を定義します。
タイプ "boolean"(false)のフィールドfがあるとします。
次の表現を定義します。
タイプ「number」のフィールドfがあるとします。
次の表現を定義します。
タイプ "string"のフィールドfがあるとします。
次の表現を定義します。
タイプ「ObjectId」のフィールドfがあるとします。
次の表現を定義します。
「オブジェクト」と「配列」の2つのタイプが残ります。 基本的に、これらの型は、より単純な型の値の「コンテナ」です。 したがって、すでに説明したルールを単純に再帰的に適用し、これらのコンテナーの要素のビューを取得できます。 唯一の微妙な点-タイプ「配列」のコンテナ内の要素の順序を保持する方法を考え出す必要があります。 これは簡単に解決されます。すべての要素には走査順序で番号が付けられ、プレゼンテーションは同じ順序で行われます。
タイプ「オブジェクト」(空)のフィールドfがあるとします。
次の表現を定義します。
タイプ「オブジェクト」のフィールドfがあるとします。
次の表現を定義します。
タイプ「配列」(空)のフィールドfがあるとします。
次の表現を定義します。
タイプ「配列」のフィールドfがあるとします。
次の表現を定義します。
^ MonCache(<db>、<collection>、<document id>、...)の代わりに書くだけです
@(...) 。
タイプ「null」のフィールドfがあるとします。
f: null
次の表現を定義します。
@("f", "t") = "null"
タイプ「boolean」(true)のフィールドfがあるとします。
f: true
次の表現を定義します。
@("f", "t") = "boolean" @("f", "v") = 1
タイプ "boolean"(false)のフィールドfがあるとします。
f: false
次の表現を定義します。
@("f", "t") = "boolean" @("f", "v") = 0
タイプ「number」のフィールドfがあるとします。
f: 3.14
次の表現を定義します。
@("f", "t") = "number" @("f", "v") = 3.14
タイプ "string"のフィールドfがあるとします。
f: 'Habrahabr.ru'
次の表現を定義します。
@("f", "t") = "string" @("f", "v") = "Habrahabr.ru"
タイプ「ObjectId」のフィールドfがあるとします。
f: ObjectId('56b43c20af9c4f3fe2cc2908')
次の表現を定義します。
@("f", "t") = "objectid" @("f", "v") = "56b43c20af9c4f3fe2cc2908"
「オブジェクト」と「配列」の2つのタイプが残ります。 基本的に、これらの型は、より単純な型の値の「コンテナ」です。 したがって、すでに説明したルールを単純に再帰的に適用し、これらのコンテナーの要素のビューを取得できます。 唯一の微妙な点-タイプ「配列」のコンテナ内の要素の順序を保持する方法を考え出す必要があります。 これは簡単に解決されます。すべての要素には走査順序で番号が付けられ、プレゼンテーションは同じ順序で行われます。
タイプ「オブジェクト」(空)のフィールドfがあるとします。
f: {}
次の表現を定義します。
@("f", "t") = "object"
タイプ「オブジェクト」のフィールドfがあるとします。
f: { site: 'Habrahabr.ru', topic: 276391 }
次の表現を定義します。
@("f", "t") = "object" @("f", "v", "site", "t") = "string" @("f", "v", "site", "v") = "Habrahabr.ru" @("f", "v", "topic", "t") = "number" @("f", "v", "topic", "v") = 276391
タイプ「配列」(空)のフィールドfがあるとします。
f: []
次の表現を定義します。
@("f", "t") = "array"
タイプ「配列」のフィールドfがあるとします。
f: [ 'Habrahabr.ru', 276391 ]
次の表現を定義します。
@("f", "t") = "array" @("f", "v", 0, "t") = "string" @("f", "v", 0, "v") = "Habrahabr.ru" @("f", "v", 1, "t") = "number" @("f", "v", 1, "v") = 276391
Cachéとの対話のスキーム
InterSystemsCachéを操作するための論理的でシンプルなドライバーの選択は、Node.jsドライバーの選択でした( ドキュメントWebサイトで 、Cachéと対話するための他のドライバーを確認できます)。 ただし、ドライバーが十分ではなかったことはすぐに注目に値します。 私はいくつかの挿入を行い、これらすべてを1つのトランザクションで行いたいと思いました。 したがって、MongoDB APIをシミュレートするために使用されたCachéObjectScriptクラスのセットを開発することが決定されましたが、Cachéの側で開発されました。
CachéNode.jsドライバは、Cachéのクラスにアクセスできませんでしたが、Cachéでプログラム呼び出しを行うことができました。 この事実により、小さなプログラムが作成されました。これは、Cachéのドライバとクラス間の橋渡しの一種です。
その結果、スキームは次のようになりました。

プロジェクトの作業の一環として、特別なNSNJSON形式(Not So Normal JSON)が開発されました。これにより、Cachéのドライバを通じてObjectId、null、true、falseをドラッグできます。 この形式は、 GitHub-NSNJSONの対応するページにあります 。 Habrahabrでは、この形式に特化した3つの記事をレイアウトしました。
- 複雑な単純化されたJSON 。
- ブラケットのファンのためのJSON 。
-NSNJSON。 道(最終記事) 。
モンカシェの機会
ドキュメント検索操作を実行する場合、次の基準がサポートされます。
- $ eq-等価性;
- $ neは同等ではありません。
- $ not-基準の否定。
- $ lt-より小;
- $ gt-より大きい;
- $存在 -存在。
ドキュメントの更新操作中、次の演算子がサポートされます。
- $ set-値の設定。
- $ inc-指定された値で値を増分します。
- $ mul-値に特定の値を掛けます。
- $ unset-値を削除します;
- $ rename-値の名前を変更します。
例
このコードを公式ドライバーページから取得し、少しやり直しました。
var insertDocuments = function(db, callback) { var collection = db.collection('documents'); collection.insertOne({ site: 'Habrahabr.ru', topic: 276391 }, function(err, result) { assert.equal(err, null); console.log("Inserted 1 document into the document collection"); callback(result); }); } var MongoClient = require('mongodb').MongoClient , assert = require('assert'); var url = 'mongodb://localhost:27017/myproject'; MongoClient.connect(url, function(err, db) { assert.equal(null, err); console.log("Connected correctly to server"); insertDocument(db, function() { db.close(); }); });
このコードは、MonCachéで動作するように簡単に変更できます!
ドライバーを変更するだけです!
// var MongoClient = require('mongodb').MongoClient var MongoClient = require('moncache-driver').MongoClient
このコードを実行すると、グローバル^ MonCacheは次のようになります。
^MonCache("myproject","documents")=1 ^MonCache("myproject","documents",1,"_id","t")="objectid" ^MonCache("myproject","documents",1,"_id","v")="b18cd934860c8b26be50ba34" ^MonCache("myproject","documents",1,"site","t")="string" ^MonCache("myproject","documents",1,"site","v")="Habrahabr.ru" ^MonCache("myproject","documents",1,"topic","t")="number" ^MonCache("myproject","documents",1,"topic","v")=267391
デモ
特に、小さなデモアプリケーション ( sources )が起動され、これもNode.jsに実装され、サーバーを再起動してソースコードを変更することなく、MongoDB Node.jsからMonCachéNode.jsにドライバーを変更する方法を示しました。 このアプリケーションは、製品やオフィスでCRUD操作を実行するための小さなデモプラットフォームであり、構成を変更する(ドライバーを変更する)インターフェイスでもあります。
サーバーを使用すると、構成で選択したストレージ(CachéまたはMongoDB)に格納される製品とオフィスを作成できます。
[ 注文 ]タブに注文のリストが表示されます。 レコードを作成しましたが、フォームを完成しませんでした。プロジェクト( source )を支援できます。
[ 構成]ページに移動して、構成を変更できます。 ページには「MongoDB」と「MonCache」の2つのボタンがあります。 適切なボタンをクリックして、必要な構成を選択します。 構成を変更すると、クライアントアプリケーションはデータソース(アプリケーションと実際に使用されるドライバーを分離する抽象化)に再接続します。
結論
結論として、私は主な質問に答えます。 はい! 実際、基本操作のパフォーマンスをわずかに向上させることができました。
MonCachéプロジェクトはGitHubで公開されており、MITの下でライセンスされています。
簡単な説明
- Cachéをインストールする
- Cachéで必要なすべてのMonCachéコンポーネントをダウンロードします
- CachéでMONCACHEリージョンを作成する
- パスワードehcacnomを使用して、Cachéでmoncacheユーザーを作成します。
- 環境変数MONCACHE_USERNAME = moncacheを作成します
- 環境変数MONCACHE_PASSWORD = ehcacnomを作成します
- 環境変数MONCACHE_NAMESPACE = MONCACHEを作成します
- プロジェクトの依存関係を「mongodb」から「moncache-driver」に変更します
- プロジェクトを立ち上げてください! :-)
アカデミックプログラムシステム
InterSystemsテクノロジーを使用して独自の研究プロジェクトを実装することに関心がある場合は、InterSystemsアカデミックプログラム専用の専門サイトにアクセスできます 。