对于Node.js和React.js的开发者 一个新的Neo4j电影模板


让我们直接开始吧。你是一个对 Neo4j 感兴趣的JavaScript开发人员,想要建立一个网络应用、微服务或移动应用。

你已经阅读了Neo4j,玩了一些数据集,并且知道足够的 Cypher ,可以开始工作。现在,你正在寻找一个演示应用程序或模板来启动球 - 你来对地方了。

进入Neo4j Movies模板

Neo4j Movies模板的内容。

电影演示应用程序

模型。 这个项目使用一个经典的Neo4j数据集:电影数据库。它包括 MoviePersonGenreKeyword 个节点,通过关系连接,如下图所示。
Learn all about how to use Node.js and React.js with Neo4j with this new Movies template

API。 应用程序的Node.js部分与数据库接口,并通过RESTful API将数据呈现给React.js前端。

前端。 前端,在这种情况下是用React.js构建的,消费由Express.js API提供的数据,并向用户展示一些视图,包括主页、电影详情页和人物详情页。

设置

为了让项目运行, 克隆 repo 然后查看项目的 README 以了解特定环境的设置说明。

使用neo4j-import将CSV文件导入数据库

在这个例子中,每个节点类型和关系类型都有自己的 CSV 文件。为了创建和查看电影图。
  • 下载并安装Neo4j
  • 导入节点
  • 导入关系
  • 启动数据库!
如果你是在Unix上,并且下载了.tar版本的Neo4j,你应该使用stock neo4j-import

如果你在Mac或Windows上,并且下载了.dmg或.exe版本的Neo4j,请尝试将导入脚本的 $NEO4J_HOME/bin/neo4j-import 部分替换成 适当的替换 。例如,这将是Neo4j 3.0.3上Windows的替代命令:

"C:\Program Files\Neo4j Community\jre\bin\java" -cp "C:\Program Files\Neo4j
Community\bin\neo4j-desktop-3.0.3.jar" org.neo4j.tooling.ImportTool --into database/ 
--nodes:Person csv/person_node.csv --nodes:Movie csv/movie_node.csv --nodes:Genre
csv/genre_node.csv --nodes:Keyword csv/keyword_node.csv --relationships:ACTED_IN
csv/acted_in_rels.csv --relationships:DIRECTED csv/directed_rels.csv 
--relationships:HAS_GENRE csv/has_genre_rels.csv --relationships:HAS_KEYWORD csv/has_keyword_rels.csv --relationships:PRODUCED csv/produced_rels.csv 
--relationships:WRITER_OF csv/writer_of_rels.csv --delimiter ";" --array-delimiter "|" 
--id-type INTEGER

启动Node.js后端

Neo4j驱动的Express.js API位于 api 目录中。  
The Neo4j and Express.js API

为了运行API,你需要打开一个新的终端标签,并移动到 api 目录下使用 npm install 安装依赖项:

cd api
npm install

如果你的终端不知道命令 npm ,请确保你已经安装了Node.js,也许选择 nvm 来管理你的Node.js的版本(我使用v6.2.1)。  

在你安装了你的依赖项并运行了你的数据库之后,用以下方法启动API。

node app.js

在API的文档页面上, http://localhost:3000/docs/ ,选择 /genres ,然后按 Try it out! 按钮来查看API调用样本。  
The Node.js and Neo4j API documentation

如果你遇到问题,确保你的数据库确实在运行,并且你已经在 api/config.js 文件中输入了你的数据库凭证。

The Config.js API

启动React.js前端

The React.js front-end

在数据库和Express.js后端运行的情况下,打开一个新的终端标签或窗口,移到项目的 /web 子目录下。安装 bower npm 依赖项,然后通过运行 gulp 来启动应用程序(如果你是第一次使用gulp,请阅读gulpjs.com上的 "入门")。

npm install
bower install
gulp

http://localhost:4000/ 上,你应该看到电影应用程序的主页,显示三部特***和一些 Action 类型的成员。  
A Neo4j and JavaScript movies web app

点击一部电影可以看到电影的详细页面。

A sample movie app using JavaScript and Neo4j

点击一个人,可以看到这个人的相关人物和这个人演过的电影、导演、编剧或制片人。

An Andy Wachowski example in a Neo4j and JavaScript sample movies app

近距离观察

使用JavaScript Neo4j Bolt驱动

让我们仔细看看我们从JavaScript Bolt驱动得到什么样的响应。在这个应用程序中,对数据库的调用是由 /api/neo4j/dbUtils.js 处理的,下面逐条描述。  

导入依赖关系,包括Neo4j驱动和连接驱动到数据库。

var nconf = require('../config');


var neo4j = require('neo4j-driver').v1;
var driver = neo4j.driver(nconf.get('neo4j-local'), neo4j.auth.basic(nconf.get('USERNAME'), nconf.get('PASSWORD')));

让我们看一下我们如何要求数据库返回数据库中的所有流派。 getAll (如下)提交一个Cypher查询,并将数据库中的结果通过 _manyGenres 函数传递,该函数将结果映射为可用的形式,并处理将Neo4j的整数转换为JavaScript数字的问题。 
/api/models/genres.js

var _ = require('lodash');
var Genre = require('../models/neo4j/genre');


var getAll = function(session) {
  return session.run('MATCH (genre:Genre) RETURN genre')
    .then(_manyGenres);
};


var _manyGenres = function (result) {
  return result.records.map(r => new Genre(r.get('genre')));
};


module.exports = {
  getAll: getAll
};
/api/models/neo4j/genre.js

// extracts just the data from the query results


var _ = require('lodash');


var Genre = module.exports = function (_node) {
  _.extend(this, _node.properties);
  if (this.id) { 
    this.id = this.id.toNumber();
  };
};
;

进入的查询。 
MATCH (genre:Genre) RETURN genre

完全未经处理的记录出来了。 
{ records:
   Record {
  keys: [ 'genre' ],
  length: 1,
  _fields: [ Node {
    identity: Integer { low: 737, high: 0 },
   labels: [ 'Genre' ],
   properties: { name: 'Suspense', id: Integer { low: 3270, high: 0 } } ],
  _fieldLookup: { genre: 0 } },


      ... // more records
],
  summary:
   ResultSummary {
     statement: { text: 'MATCH (genre:Genre)\nRETURN genre', parameters: {} },
     statementType: 'r',
     updateStatistics: StatementStatistics { _stats: [Object] },
     plan: false,
     profile: false,
     notifications: [] } }

为了抓住 genre 节点,我们将使用 record.get('genre') 来获得以下数据。 
Node {
  identity: Integer { low: 735, high: 0 },
  labels: [ 'Genre' ],
  properties: { name: 'Family', id: Integer { low: 1258, high: 0 } } }

这样做比较好,但仍然无法使用。我们想把下面这样的结果输入一个数组,以呈现给前端。 
 {
    "name": "Family",
    "id": 1258
 }

返回函数解析了混乱的结果 int