Skip to content
  1. Examples

Neo4j Cypher

This exame shows how to connect to a neo4j database, run cypher queries and display the results in Ogma.
This example actually uses pre-recorded responses of a neo4j@v3.0.4 server. To use this example with your database, omit the stub file and follow the instructions the example code.

Use neo4j javascript driver to create a driver and a session.
Then use Ogma's parse.neo4j() function to parse the results into Ogma's RawGraph format.

Double click on a node to expand the graph.

js
import Ogma from '@linkurious/ogma';
// this is a stub using pre-recorded server responses, don't use it
import * as neo4j from './neo4j-stub';

// for the actual server connection, use next line
// import neo4j from 'neo4j-driver';

// highlight the Cypher query
hljs.initHighlightingOnLoad();

const ogma = new Ogma({
  container: 'graph-container'
});

// Create a connection to the Neo4j database.
// change this URL to your local Neo4j database instance
const driver = neo4j.driver(
  'bolt://localhost:7687',
  neo4j.auth.basic('example', 'b.SKbqdJ4W59Zk.dQqSZRuJ1NoxwWcz'),
  { encrypted: true } // remove this to run it locally
);
const session = driver.session();

const toggleLoading = () => {
  const el = document.querySelector('#info');
  const enable = el.style.display;
  el.style.display = enable === 'block' ? 'none' : 'block';
};

const getStartTemplate = () =>
  ['MATCH (n)', 'OPTIONAL MATCH (n)-[r]-(m)', 'RETURN n,r,m', 'LIMIT 5'].join(
    '\n'
  );

const getExpandQuery = id =>
  [
    'MATCH (n)-[r]-(m)',
    'WHERE id(n) = ' + id,
    'RETURN n,r,m',
    'LIMIT 100'
  ].join('\n');

const updateCypherQuery = query => {
  const codeBlock = document.querySelector('#query-text');
  codeBlock.innerText = query;
  hljs.highlightBlock(codeBlock);
};

const res = {};

const sendQuery = id => {
  const query = id ? getExpandQuery(id) : getStartTemplate();
  toggleLoading();
  updateCypherQuery(query);
  return session
    .run(query)
    .then(result => {
      res[query] = JSON.stringify(result);
      return Ogma.parse.neo4j(result);
    })
    .then(graph => {
      toggleLoading();
      return ogma.addGraph(graph);
    })
    .then(() => layout());
};

const layout = () =>
  ogma.layouts.forceLink({
    duration: 550,
    locate: { padding: 80 }
  });

// Define what to use as node and edge captions.
ogma.styles.addEdgeRule({
  text: {
    content: e => e.getData('neo4jType')
  },
  color: e => {
    const labels = e.getData('neo4jType');
    if (labels.includes('ACTED_IN')) {
      return '#22b455';
    }
    if (labels.includes('DIRECTED')) {
      return '#80ce87';
    }
    if (labels.includes('PRODUCED')) {
      return '#92e5a1';
    }
  }
});

ogma.styles.addNodeRule({
  text: {
    content: n => {
      if (n.getData('neo4jLabels').includes('Movie')) {
        return n.getData('neo4jProperties.title');
      }
      if (n.getData('neo4jLabels').includes('Person')) {
        return n.getData('neo4jProperties.name');
      }
    }
  },
  icon: {
    content: n => {
      if (n.getData('neo4jLabels').includes('Movie')) {
        return '\uf008';
      }
      if (n.getData('neo4jLabels').includes('Person')) {
        return '\uf007';
      }
    },
    font: 'Font Awesome 5 Free',
    color: 'black',
    minVisibleSize: 0
  },
  outerStroke: {
    color: '#204829',
    width: 2
  },
  color: 'white'
});

ogma.events.on('doubleclick', evt => {
  if (evt.target && evt.target.isNode) {
    sendQuery(evt.target.getId());
  }
});

document.querySelector('#layout').addEventListener('click', evt => {
  evt.preventDefault();
  layout();
});

sendQuery();

// close the session before unloading the page
document.addEventListener('onbeforeunload', evt => session.close());
html
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />

  <script
    src="https://cdn.jsdelivr.net/npm/neo4j-driver@4.0.1/lib/browser/neo4j-web.min.js"></script>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/solid.min.css" rel="stylesheet" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/highlight.min.js">
  </script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/styles/default.min.css"/>
  <script type="text/javascript"
  src="https://unpkg.com/highlightjs-cypher/dist/cypher.min.js">
  </script>
  <link type="text/css" rel="stylesheet" href="styles.css">
</head>

<body>
  <div id="graph-container"></div>
  <div class="toolbar">
    <h3>Current cypher query</h3>
    <pre><code class="cypher" id="query-text"></code></pre>
    <div class="controls">
      <button id="layout" class="btn menu">Layout</button>
    </div>
  </div>
  <div id="info">loading...</div>
  <script src="index.js"></script>
</body>

</html>
css
#graph-container {
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  position: absolute;
  margin: 0;
  overflow: hidden;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
}

#info {
  position: absolute;
  color: #fff;
  background: #141229;
  font-size: 12px;
  font-family: monospace;
  padding: 5px;
  top: 0;
  left: 0;
  white-space: pre;
}

.toolbar {
  display: block;
  position: absolute;
  top: 20px;
  right: 20px;
  padding: 10px;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);
  border-radius: 4px;
  background: #ffffff;
  color: #222222;
  font-weight: 300;
  min-width: 200px;
}

.toolbar h3 {
  display: block;
  font-weight: 300;
  border-bottom: 1px solid #ddd;
  color: #606060;
  font-size: 1rem;
  font-family: Arial, Helvetica, sans-serif;
}

.controls {
  text-align: center;
  margin-top: 5px;
}

.btn {
  padding: 6px 8px;
  background-color: white;
  cursor: pointer;
  font-size: 18px;
  border: none;
  border-radius: 5px;
  outline: none;
}

.btn:hover {
  color: #333;
  background-color: #e6e6e6;
}

.menu {
  border: 1px solid #ddd;
  width: 80%;
  font-size: 14px;
  margin-top: 10px;
}
js
// * Neo4j driver stub *
//
// Do not use this file! It's only purpose is
// to make this demo work smoothly with a static
// pre-recorded server responses

export const auth = {
  basic(db, password) {
    return new BasicAuth(db, password);
  }
};

class BasicAuth {
  constructor(db, password) {
  }
}

class Session {
  constructor(driver) {
    this._driver = driver;
    this._data = null;
    this._ready = fetch('files/movies-neo4j.json')
      .then(r => r.json())
      .then(responses => this._data = responses)
      .then(() => console.log('data loaded'));
  }

  run(query) {
    return this._ready
      .then(() => this._data[query] || '{ "records": [] }')
  }
}

class Driver {
  session() {
    return new Session(this);
  }

  close() {
    return Promise.resolve();
  }
}

export const driver = (url, auth) => new Driver(url, auth);