今回からは、JavaScript(TypeScript)を使って指定のPerson
のリレーションを検索・表示する簡易アプリを作成していきたいと思います。
アプリの作成を通して、JavaScriptとNeo4jの連携について解説していきたいと思います。
今回の記事では、JavaScriptとNeo4jの連携環境のセットアップし、ターゲット選択用のセレクタを実装していきます。
ターゲット選択用のセレクタには、対象候補の自動補完機能も実装したいと思います。
↓ 「Dockerで試すNeo4j」シリーズ記事一覧はこちら
目次
- はじめに
- 注意事項
- 構成
- React+TypeScript環境をインストール
- 必要なパッケージをインストール
- 環境変数を定義
- 型定義
- Neo4jドライバを取得
- 全ての「Person」ノードを取得
- ターゲット選択用のセレクタを追加
- 仕上げ
- 動作確認
- サンプルコード
- まとめ
はじめに
今回の記事では、以下の記事で追加したデータを使用します。
データを追加していない場合は、上記の記事を参考にデータを追加してください。
注意事項
トライアルという事で、クライアントからNeo4jにアクセスしていますが、アプリを公開する場合などはサーバ経由でアクセスするようにするなど、調整してください。
構成
セットアップを進める前に、最終的なファイル構成を紹介しておきたいと思います。
最終的には、以下のようなファイル構成となります。
ここで、次回以降に追加するファイルも含んでいます。
また、特にファイルの追加や変更をしない、public
などのディレクトリの中身は表示していません。
React+TypeScript環境をインストール
それでは、早速、JavaScriptとNeo4jの連携環境のセットアップしていきます。
JavaScriptの環境のベースとしてReact+TypeScript環境を使用したいと思います。
以下のコマンドを実行して、React+TypeScript環境をインストールしてください。
npx create-react-app . --template typescript
React+TypeScript環境の詳細については、以下のページを参照してください。
必要なパッケージをインストール
次に、必要になるパッケージをインストールしたいと思います。
Neo4jにアクセスするためのパッケージとしてneo4j-driver
、UI用にmaterial-ui
をインストールします。
yarn add @material-ui/core @material-ui/lab neo4j-driver
環境変数を定義
ここからは、ターゲット選択用のセレクタの実装を進めて行きます。
まずは、アプリ中で使用する環境変数を定義します。
プロジェクトルートに.env
ファイルを追加して、以下のように記述してください。
REACT_APP_NEO4J_URL=bolt://localhost:57687 REACT_APP_NEO4J_USER=test REACT_APP_NEO4J_PW=example
ここでは、Neo4jへのアクセス情報を設定しています。
以下の記事で追加したアプリ用ユーザをアクセスに使用します。
型定義
次に、コード中で使用する型をまとめて定義しておきます。
src/packages/@types
ディレクトリを作成してApp.d.ts
ファイルを追加してください。
ファイルを追加したら、以下のような記述を追加してください。
import { Node as Neo4jNode } from 'neo4j-driver' export type Node<T> = | (Neo4jNode<T> & { properties: { id: string; name: string; label: string; color: string } }) | null export type Edge = { data: { source: string; target: string; relationship: string } } export type Elements = { nodes: { data: Node['properties'] }[] edges: Edge[] }
ここで、Node
型はPerson
ノードを、Edge
型はグラフ表示する際のリレーションを、Elements
型はグラフ表示用のデータの型を定義しています。
Neo4jドライバを取得
続いて、Neo4jドライバを取得する関数を定義します。
src/packages/Search/createDriver.ts
ファイルを追加して、以下のようにコードを記述してください。
import { Driver } from "neo4j-driver/types/driver"; import neo4j from "neo4j-driver"; export const createDriver = async (): Promise<Driver> => await neo4j.driver( process.env.REACT_APP_NEO4J_URL || '', neo4j.auth.basic( process.env.REACT_APP_NEO4J_USER || '', process.env.REACT_APP_NEO4J_PW || '' ) )
Neo4jへのアクセス情報には、先ほど.env
で定義した環境変数を使用しています。
全ての「Person」ノードを取得
次に、ターゲットの自動補完用に、全てのPerson
ノードを取得する関数を追加しておきます。
src/packages/Search/getAllPersons.ts
ファイルを追加して、以下のようにコードを記述してください。
import { Node } from "../@types/App"; import { QueryResult } from "neo4j-driver"; import { createDriver } from "./createDriver"; export const getAllPersons = async (): Promise<Node<any>[]> => { const driver = await createDriver() const session = await driver.session() const result: QueryResult | void = await session .run('MATCH (n:Person) RETURN n') .catch((error) => { console.log(error) }) session.close() await driver.close() return result ? result.records?.map((record) => record.get('n')) : [] }
ここで、先ほど定義したcreateDriver
関数を使用して、driver
を取得し、session
をスタートしています。
スタートしたsession
で、Neo4jクエリMATCH (n:Person) RETURN n
を実行して、全てのPerson
ノードを取得しています。
ターゲット選択用のセレクタを追加
続いて、今回の記事の本丸である、ターゲット選択用のセレクタを実装します。
ファイルsrc/packages/Search/Search.tsx
を追加して、以下のようなコードを追加してください。
import Autocomplete from "@material-ui/lab/Autocomplete"; import { Node } from "../@types/App"; import { TextField } from "@material-ui/core"; import React, { ChangeEvent, useState } from "react"; type Props = { persons: Node<any>[] | [] } export default function Search({ persons }: Props) { const [target, setTarget] = useState<Node<any>>(null) const handleTargetChange = (event: ChangeEvent<{}>, newTarget: Node<any>) => setTarget(newTarget) return <div> <Autocomplete id="target" value={target} onChange={handleTargetChange} options={persons} getOptionLabel={(person: Node<any>) => person?.properties?.id || ''} style={{ width: 300 }} renderInput={(params) => ( <TextField {...params} label="target" variant="outlined"/> )} /> </div> }
Search
コンポーネントでは、material-ui
のAutocomplete
コンポーネントを使用しています。
これにより、プロパティpersons
の内容がテキストフィールドで選択候補として表示され、検索または選択によりターゲットを選ぶことができます。
仕上げ
最後に、ここまでに作成したコードを統合したいと思います。
src/App.tsx
を以下のように書き換えてください。
import React, { useEffect, useState } from 'react'; import { Node } from "./packages/@types/App"; import { getAllPersons } from "./packages/Search/getAllPersons"; import Search from "./packages/Search/Search"; function App() { const [persons, setPersons] = useState<Node<any>[] | []>([]) useEffect(() => { (async () => setPersons(await getAllPersons()))() }, []) return ( <div> <div> <Search persons={persons}/> </div> </div> ) } export default App;
以下の部分で、ロード時にNeo4jから全てのPerson
を取得して、persons
ステートに設定しています。
useEffect(() => { (async () => setPersons(await getAllPersons()))() }, [])
設定されたpersons
はSearch
コンポーネントの自動補完の候補に追加されます。
動作確認
ターゲット選択用セレクタのコードが全て用意できたので、実際に動かして動作を確認してみます。
以下のコマンドで、Reactアプリをスタートしてください。
yarn start
アプリを起動したら、http://localhost:3000/にアクセスしてください。
ターゲット選択用のセレクタが表示されていると思うので、クリックしてみてください。
以下のようにターゲット候補のPerson
が表示されていれば実装成功です。
サンプルコード
以下のリポジトリに「Dockerで試すNeo4j」シリーズ全話分のコードを設置しています。
うまく動かない場合は、上記のリポジトリをクローンして試してみてください。
まとめ
今回の記事では、JavaScriptとNeo4jの連携環境のセットアップし、ターゲット選択用のセレクタを実装してみました。
また、アプリの作成を通して、JavaScriptとNeo4jの連携についても解説してみました。
次回は、今回実装したターゲット選択用のセレクタを使って、特定のPerson
とFOLLOW
関係があるPerson
を検索するコードを追加したいと思います。
↓ 「Dockerで試すNeo4j」シリーズ記事一覧はこちら