Meteor用のNeo4jグラフデータベースサポートドライバーの作成
Meteorでは、データを扱う作業は双方向の反応性に関連付けられています。 現時点では、組み込みのMeteor MongoDBおよびRedis(両方のドライバーはMeteorウォール内で開発されています)の反応性は100%であり、MySQLおよびMSSQL(サードパーティ開発者)に対して部分的に反応性が実装されています。
上記のデータベースの場合、接続を提供するドライバー[データ<->ビュー]がどのデータとどのクライアントを更新するかを把握できるように、どこ、どのように、いつ、どのデータが変更されたかを報告するオブザーバーによって反応性が実装されます。 Neo4jはウォッチャーとオブザーバーを奪われていますが、これは私たちを止めませんでした。 この状況から抜け出すにはどうすればよいのでしょうか。また、なぜNeo4jをカットして読む必要があるのでしょうか。
node.jsには、Neo4jメーカーの公式で同名のnpmパッケージがあり、機能が豊富ですが、ドキュメントの最初の2行では、 GraphDatabaseとクエリメソッドへの接続のみが安定して機能することを丁寧に示唆しています 。
Neo4jが必要な理由
各タスクには、このタスクを最高レベルで実行するために作成および設計されたツールが必要だと思います。 誰もが1本の釘ができることを知っています。スリッパでハンマーを打つことが、時には必要です(検索に費やした時間やハンマーを買うための資金が不当に高い場合)。 しかし、100本、さらには100,000本以上の釘については、ハンマー、できれば釘銃を入手することをお勧めします。 この場合、レコード間の関係に関するデータを保存および受信する必要があります。 データは引き続き非正規化形式でMongoDBに格納されますが、このデータの関係はNeo4jに格納されます。
すべての始まり:コネクタ
最初は、 GraphDatabaseタイプのオブジェクトを含むグローバル変数を作成することにより、npmパッケージで提供される機能がタスクに十分であると想定されていました:その時点では、データベースとの間でデータを読み書きしていました(反応性なし)。 こうして生まれたneo4jdriver-グローバルにアクセス可能なクラスNeo4jを含むパッケージ。初期化中に、ローカルまたはリモートで起動されたデータベースとの接続が作成されます。 初期化中に、単一のurlパラメーターを渡すことができます。
後に必要となったのは:
- 反応性;
- オブザーバー
- 同型-サーバーとクライアントの両方からの要求を満たす能力。
- 着信データの構造化-デフォルトでは、Neo4jは、 MATCHリクエストを適切に処理する大量のゴミを捨てます。
そして、楽しみが始まりました。
方法:反応性
2番目にリリースされたのは、MongoDBの形式の中間層を介して実装された擬似反応性の原理に基づいたneo4jreactivityパッケージです。 簡単に言えば、Neo4jでのすべてのリクエストに対して、 Mongo \ Cursorを返します。これは、リアクティブデータのソースであるか、Meteorコミュニティで一般的に呼ばれるように、REACTIVE DATA SOURCEです。
最初は、すべてがシンプルに見えました。
- リクエスト、リクエストのハッシュ、Neo4jからの応答を含むMongoDBのキャッシュコレクションを作成します。
- クライアントの場合、サブスクライブする必要があるリクエストのすべてのハッシュを含む配列を保持するセッションを作成します。
- すべての要求をMeteor.neo4j.queryメソッドに渡します。Meteor.neo4j.queryメソッドは、要求からデータベースへのハッシュを作成し、データベースから応答を受け取り、データベースに書き込み、この要求ハッシュにサブスクライブしているすべてのクライアントに送信します。
- クライアントからリクエストを起動するために、食べるMeteorメソッドを作成します! サーバー上でリクエストを実行します。
ドライバーの最初のバージョンの1つがリリースされた時点で、クライアント上で絶対にあらゆるリクエストを実行できました。 Neo4jに保存されているすべてのデータを変更、取得、または消去できます。 この問題は、 Meteor.neo4j.methods({})メソッドとMeteor.neo4j.call(methodName、opts、callback)メソッドを導入することで解決しました。これらは、標準のMeteor.methods({})の例に基づいて動作します。
if(Meteor.isServer){ Meteor.neo4j.methods({ 'GetUser': function(){ return 'MATCH (n:User {_id: {userId}}) RETURN n' } }); }; if(Meteor.isClient){ Meteor.neo4j.call('GetUser', {userId: 123}, function(error, data){ if(!error){ Session.set('theUser', data); } }); }
2番目に行ったのはプロパティMeteor.neo4j.allowClientQueryで 、これは値trueおよびfalseを取り、デフォルトはfalseです。 これにより、開発者はアプリケーションの開発およびテスト中にブラウザーコンソールで作業し、データを送信し、受信したデータを検証できます。
何らかの理由でクライアントからNeo4jへのリクエストを実行する可能性を残すことにした場合、Neo4jへのリクエストのタイプを制限できる次の機能が提供されます。 neo4j.set.allowとneo4j.set.denyの 2つのメソッドを使用できます。 両方のメソッドは、単一のパラメーター-文字列の配列を受け入れます。 さらに、配列を使用できます: Meteor.neo4j.rules.allow 、 Meteor.neo4j.rules.deny 、およびneo4j.rules.writeには現在の規則が含まれ、後者には書き込み演算子を含む配列が含まれているため、このようなショートカットを作成できます。
if(Meteor.isClient){ Meteor.neo4j.set.deny(Meteor.neo4j.rules.write); }
また、クライアントからのすべての記録要求を禁止します。 上記の段落で説明したすべてのメソッドは同型です。 サーバー側でデータの整合性がさらにチェックされるため、クライアント側からのハックは通過しません。
私たちはデータを追跡します:ブラックジャックとリスナーがいる私たちのオブザーバー
データ変更要求がクライアントでデータ更新を開始しなかったことが後に発見されました。 クライアントの1つが変更されたデータにアクセスし、MongoDBで更新を開始するまで、その結果、すべてのクライアントで反応性が機能しませんでした。 これは、変更されたデータを監視し、変更されたデータに関連するすべてのリクエストの起動を開始するオブザーバーがいなかったためです。
リスナー
neo4jdriverと呼ばれる理想的なパッケージに戻り、プロジェクト全体を消去して再度書き込みます。
- クラス構造とクラスインスタンスの初期化は、 URLをデータベースに渡す機能とともに残します。
- queryとoptsの 2つのパラメーターを取るコールバックを格納するGraphDatabase.callbacks配列を作成します 。
- GraphDatabase.listen(func)メソッドを追加します。このメソッドは、 queryとoptsの 2つのパラメーターを持つ関数を受け取り、すべての関数がGraphDatabase.callbacks配列に分類されます。
- npmパッケージに組み込まれたクエリメソッドを再割り当てし、 GraphDatabase.callbacks配列からのすべてのコールバックの起動を追加します。
反応性オブザーバー:
まず、要求構造から要求データを分離する方法を学ぶ必要があります;このために、 sensitivitiesパラメーターが導入されました。 このパラメーターには、変更される可能性のあるデータが含まれます。 Neo4jCacheCollectionのエントリは次のとおりです。
uid // Unique hashed ID of the query data // Parsed data returned from Graph query // Original Cypher query string sensitivities // Sensitive data, which contains a map of parameters, and hardcoded data into query opts // Original map of parameters for the Cypher query type // Type of query ('READ'|'WRITE') created // Creation time
オブザーバーとリスナーをバインドします。
- Neo4jへのすべてのリクエストに傍受します。
- 現在のリクエストの感度を取得します。
- 現在の要求からの感度を含むすべての読み取り要求を見つけます。
- 受信した一致の再サンプリングを開始します。
- さらに必要な反応性は、MongoDBの形式でレイヤーによって提供されます。
すべてのクライアントで、非常に簡単な方法で、データが変更されたときにデータが更新されるように管理しました。
必要なデータのみを取得します
3番目の問題は、Neo4jからのデータです。 要求したフィールドに加えて、npmパッケージが返す空のオブジェクトの束も取得します。 空のオブジェクトは非常に重く、情報が含まれていないため、保存する必要はありません。 有用なデータと要求されたデータを分離するために、データベース内のクエリ(Cypherクエリ)を解析し、要求されたデータと開発者が受け取りたいフィールドを理解するparseReturnメソッドが作成されました。 その後、要求された情報ごとに、データとメタデータを持つノードの配列を含むオブジェクトが作成されました。 ノードの関係が要求される場合、各ノードには、次のパラメーターの形式でデータを含む関係オブジェクトが含まれます。
- 拡張機能
- 始める
- 終わり
- 自己
- タイプ
お客様に更新を提供します
MongoDBでデータを更新し、Neo4jで変更を監視する方法を学びましたが、返されたデータのネストされたオブジェクトは、それ自体では更新されません。 react-varパッケージが提供する機能は私たちの助けになりました。 これを行うには、クライアントでNeo4jCacheコレクションからデータを受信するときに、データが割り当てられ、 ReactiveVarを介して返されます。 サーバーでは、コレクションから受信すると、 Neo4jCacheがPromiseから返されます。 サーバーとクライアントでは、 get()メソッドを呼び出してデータを現実的に取得するだけで十分です。 Mongo \ Cursorを取得する必要がある人のために、プロパティcursorがあります 。
例:
/* ( ) */ allUsers = Meteor.neo4j.query('MATCH (users:User) RETURN users'); /* */ var users = allUsers.get().users; /* Mongo\Cursor */ var usersCursor = allUsers.cursor; /* ( ) callback*/ var allUsers; Meteor.neo4j.query('MATCH (users:User) RETURN users', null, function(error, data){ allUsers = data.user; });
この時点で、テストアプリケーションを作成し、GitHubで公開しました。 1週間後、開発者のコミュニティがドライバーの「仕上げ」と小さなバグの修正を支援しました。 プロジェクトの改善とさらなる発展のための質問と提案を喜んでいます。 ご清聴ありがとうございました。
参照:
- NPMパッケージ: node-neo4j
- Neo4j Meteorドライバー: neo4jdriver
- Neo4j流星反応性レイヤー: neo4jreactivity
- MeteorでNeo4jを使用する例: Neo4jベースのリーダーボードMeteorアプリ
PS現時点では、Neo4jはプロジェクトの開発に積極的に関与しており、Meteorのこのドライバーを公式として認識しています。