Just for Node.js & React.js Developers: A New Neo4j Movies Template


Let’s jump right into it. You’re a JavaScript developer interested in Neo4j and want to build a web app, microservice or mobile app. You’ve already read up on Neo4j, played around with some datasets, and know enough Cypher to get going. Now you’re looking for a demo app or template to get the ball rolling – you’ve come to the right place.

Enter the Neo4j Movies Template

  What comes with the Neo4j Movies Template:

The Movie Demo Application

  The Model: This project uses a classic Neo4j dataset: the movie database. It includes Movie, Person, Genre and Keyword nodes, connected by relationships as described in the following image:
Learn all about how to use Node.js and React.js with Neo4j with this new Movies template
The API: The Node.js portion of the application interfaces with the database and presents data to the React.js front-end via a RESTful API. The Front-end: The front-end, in this case is built in React.js, consumes the data presented by the Express.js API and presents some views to the user, including the home page, a Movie detail page and a Person detail page.

Setting Up

  To get the project running, clone the repo then check the project’s README for environment-specific setup instructions.
Use neo4j-import to Import CSV Files into the Database
  In this example app, every node type and relationship type has its own CSV file. In order to create and view the movie graph:
    • Download and install Neo4j
    • Import the nodes
    • Import the relationships
    • Start the database!
If you’re on Unix and downloaded the .tar version of Neo4j you should be fine using stock neo4j-import. If you’re on Mac or Windows and downloaded the .dmg or .exe versions of Neo4j, try replacing the $NEO4J_HOME/bin/neo4j-import part of the import script with the appropriate replacement. For example, this would be the alternate command for Windows on Neo4j 3.0.3:
"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
 
Start the Node.js Backend
  The Neo4j-powered Express.js API lives in the api directory.
The Neo4j and Express.js API
In order to run the API, you’ll need to open a new terminal tab and move to the api directory install dependencies using npm install:
cd api
npm install
  If your terminal does not know the command npm, make sure you have installed Node.js, perhaps choosing nvm to manage your version of Node.js (I’m using v6.2.1). After you’ve installed your dependencies and have your database running, start the API using:
node app.js
  Over on the API’s documentation page, https://localhost:3000/docs/, select on /genres and then press the Try it out! button to see a sample API call.
The Node.js and Neo4j API documentation
If you run into problems, make sure your database is actually running and that you’ve entered your database credentials in the api/config.js file.
The Config.js API
Start the React.js Front-end
 
The React.js front-end
With the database and Express.js backend running, open a new terminal tab or window and move to the project’s /web subdirectory. Install the bower and npm dependencies, then start the app by running gulp (read the “getting started” on gulpjs.com if this is your first time using gulp).
npm install
bower install
gulp
  Over on https://localhost:4000/, you should see the homepage of the movie app, displaying three featured movies and some members of the Action genre.
A Neo4j and JavaScript movies web app
Click on a movie to see the movie detail page:
A sample movie app using JavaScript and Neo4j
Click on a person to see that person’s related persons and movies the person has acted in, directed, written or produced:
An Andy Wachowski example in a Neo4j and JavaScript sample movies app

A Closer Look

 
Using the JavaScript Neo4j Bolt Driver
  Let’s take a closer look at what sort of responses we get from the JavaScript Bolt driver. In this app, calls to the database are handled by /api/neo4j/dbUtils.js, described piece by piece below. Import dependencies, including the Neo4j driver and connecting the driver to the database:
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')));
  Let’s look at how we would ask the database to return all the genres in the database. getAll (below) submits a Cypher query and passes the result from the database through the _manyGenres function, which maps the results into a usable form and deals with converting Neo4j integers to JavaScript numbers.
/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();
  };
};
;
  The query going in:
MATCH (genre:Genre) RETURN genre
  Completely unprocessed records coming out:
{ 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: [] } }
  In order to grab the genre node, we would use record.get('genre') to get the following data:
Node {
  identity: Integer { low: 735, high: 0 },
  labels: [ 'Genre' ],
  properties: { name: 'Family', id: Integer { low: 1258, high: 0 } } }
  This is better, but still not usable. We want to feed results like the following into an array to present to the frontend.
 {
    "name": "Family",
    "id": 1258
 }
  The return function parses the messy results into the data we need:
var _manyGenres = function (result) {
  return result.records.map(r => new Genre(r.get('genre')));
};
  Voila! An array of genres appears at /genres.

Beyond the /Genres Endpoint

  Of course, an app that just shows movie genres isn’t very interesting. Take a look at the routes and models used to build the home page, movie detail page and person detail page.

Next Steps

 
    • Fork the repo and hack away! Find directors that work with multiple genres, or find people who happen to work with each other often as writer-director pairs.
    • Find a way to improve the template or the JS driver? Make a GitHub Issue and/or submit a pull request.

Resources

 
Found a bug? Got stuck?
 
    • The neo4j-users #help channel will be happy to assist you
    • Make a GitHub issue on the driver or app repos
Neo4j
 
Express.js
 
React.js
   
Need a primer on Neo4j? Get your free copy of the Learning Neo4j ebook and catch up to speed with the world’s leading graph database. Learn Neo4j Today