Neo4j DB reactive layer for Meteor
Neo4j reactivity creates mongodb layer between neo4j and your Meteor based application. All write requests is synchronized between all clients. Please see this package on atmospherejs.com .
Example App
The basic example is build on top of --example leaderboard
- the Meteor Leaderboard Neo4j Example App
Description
Due to security lack we decide separate server side with queries, and client side with handlers via methods.
To create method use Meteor.neo4j.methods({'object of functions'})
with functions which returns query string (see example below).
To call and handle database answer use: Meteor.neo4j.call('methodName', {'A map of parameters for the Cypher query'}, function(error, data){...})
Install the driver
meteor add ostrio:neo4jreactivity
Known issues:
- Error: Neo4jCacheCollection.upsert in v2.2.*: - You need to disable default authentication in Neo4j-2.2.*:
- Open file
/Your_Neo4j-2.2.0_install_path/conf/neo4j-server.properties
- Change line:
dbms.security.auth_enabled=true
(to false)
- Open file
Usage example:
In Server Methods
1#CoffeeScript 2Meteor.neo4j.methods 3 getUsersFriends: () -> 4 return 'MATCH (a:User {_id: {userId}})-[relation:friends]->(b:User) ' + 5 'OPTIONAL MATCH (b:User)-[subrelation:friends]->() ' + 6 'RETURN relation, subrelation, b._id AS b_id, b'
In Helper
1#CoffeeScript 2Template.friendsNamesList.helpers 3 userFriends: () -> 4 5 Meteor.neo4j.call 'getUsersFriends', {userId: '12345'}, (error, data) -> 6 if error 7 #handle error here 8 throw new Meteor.error '500', 'Something goes wrong here', error.toString() 9 else 10 Session.set 'currenUserFriends', data 11 12 return Session.get 'currentUserFriens'
In Template:
1<template name="friendsNamesList"> 2 <ul> 3 {{#each userFriends.b}} 4 <li>{{b.name}}</li> 5 {{/each}} 6 </ul> 7</template>
About security
By default query execution is allowed only on server, but for development purpose (or any other), you may enable it on client:
1#Write this line in /lib/ directory to execute this code on both client and server side 2Meteor.neo4j.allowClientQuery = true 3#Do not forget about minimum security, deny all write queries 4Meteor.neo4j.set.deny Meteor.neo4j.rules.write
To allow or deny actions use neo4j.set.allow(['array of strings'])
and neo4j.set.deny(['array of strings'])
1#CoffeeScript 2Meteor.neo4j.set.allow ['create', 'Remove'] 3Meteor.neo4j.set.deny ['SKIP', 'LIMIT'] 4 5#OR to allow or deny all 6Meteor.neo4j.set.allow '*' 7Meteor.neo4j.set.deny '*' 8 9#To deny all write operators 10Meteor.neo4j.set.deny Meteor.neo4j.rules.write 11 12#default rules 13Meteor.neo4j.rules = 14 allow: ['RETURN', 'MATCH', 'SKIP', 'LIMIT', 'OPTIONAL', 'ORDER BY', 'WITH', 'AS', 'WHERE', 'CONSTRAINT', 'UNWIND', 'DISTINCT', 'CASE', 'WHEN', 'THEN', 'ELSE', 'END', 'CREATE', 'UNIQUE', 'MERGE', 'SET', 'DELETE', 'REMOVE', 'FOREACH', 'ON', 'INDEX', 'USING', 'DROP'] 15 deny: []
Execute query on client side:
1#Write this line in /lib/ directory to execute this code on both client and server side 2Meteor.neo4j.allowClientQuery = true 3 4#Client code 5getAllUsers = () -> 6 return Session.get('allUsers', Meteor.neo4j.query('MATCH (a:User) RETURN a'));
For more info see: neo4jdriver and node-neo4j
Code licensed under Apache v. 2.0: node-neo4j License
Testing & Dev usage
Local usage
- Download (or clone) to local dir
- Stop meteor if running
- Run
mrt link-package [*full path to folder with package*]
in a project dir - Then run
meteor add ostrio:neo4jreactivity
- Run
meteor
in a project dir - From now any changes in ostrio:neo4jreactivity package folder will cause rebuilding of project app
Understanding the package
After installing ostrio:neo4jreactivity
package - you will have next variables:
Meteor.Neo4j;
Meteor.N4JDB;
Meteor.neo4j;
var Neo4j;
1/* 2 * Server only 3 * @class 4 * @name Neo4j 5 * @param url {string} - url to Neo4j database 6 * Note: It’s better to store url in environment 7 * variable, 'NEO4J_URL' or 'GRAPHENEDB_URL' - 8 * so it will be automatically picked up by our driver 9 * 10 * @description Run it to create connection to database 11 */ 12var N4JDB = new Neo4j();
Newly created object has next functions, you will use:
1/* @name query */ 2Meteor.N4JDB.query('MATCH (n:User) RETURN n', null /* A map of parameters for the Cypher query */, function(err, data){ 3 Session.set('allUsers', data); 4}); 5 6/* @name listen */ 7Meteor.N4JDB.listen(function(query, opts){ 8 console.log('Incoming request to neo4j database detected!'); 9});
var neo4j;
1/* Both (Client and Server) 2 * @object 3 * @name neo4j 4 * @description Application wide object neo4j 5 */ 6Meteor.neo4j; 7Meteor.neo4j.allowClientQuery = true; /* Allow/deny client query executions */ 8Meteor.neo4j.connectionURL = null; /* Set custom connection URL to Neo4j DB, Note: It’s better to store url in environment variable, 'NEO4J_URL' or 'GRAPHENEDB_URL' - so it will be automatically picked up by the driver */
neo4j
object has multiple functions, you will use:
1/* @namespace neo4j.set 2 * @name allow 3 * @param rules {array} - Array of Cypher operators to be allowed in app 4 */ 5Meteor.neo4j.set.allow(rules /* array of strings */); 6 7/* @namespace neo4j.set 8 * @name deny 9 * @param rules {array} - Array of Cypher operators to be forbidden in app 10 */ 11Meteor.neo4j.set.deny(rules /* array of strings */); 12 13 14/* 15 * @function 16 * @namespace neo4j 17 * @name query 18 * @param query {string} - Cypher query 19 * @param opts {object} - A map of parameters for the Cypher query 20 * @param callback {function} - Callback function(error, data){...}. Where is data is [REACTIVE DATA SOURCE] 21 * So to get data for query like: 22 * 'MATCH (a:User) RETURN a', you will need to: 23 * data.a 24 * @param settings {object} - {returnCursor: boolean} if set to true, returns Mongo\Cursor 25 * @description Isomorphic Cypher query call 26 * @returns Mongo\Cursor or ReactiveVar [REACTIVE DATA SOURCE] 27 * 28 * @note Please keep in mind what on client it returns ReactiveVar, but on server it returns just data, see difference in usage at example below 29 * 30 */ 31allUsers = Meteor.neo4j.query('MATCH (users:User) RETURN users'); 32var users = allUsers.get().users; 33 34/* or via callback, on callback there is no need to run `get()` method */ 35var users; 36Meteor.neo4j.query('MATCH (users:User) RETURN users', null, function(error, data){ 37 users = data.users; 38}); 39 40 41/* 42 * Server only 43 * @name methods 44 * @param methods {object} - Object of methods, like: { methodName: function(){ return 'MATCH (a:User {name: {userName}}) RETURN a' } } 45 * @description Create server methods to send query to neo4j database 46 */ 47Meteor.neo4j.methods({ 48 'GetAllUsers': function(){ 49 return 'MATCH (users:User) RETURN users'; 50 } 51}); 52 53 54/* 55 * Client only 56 * @name call 57 * @description Call for server method registered via neo4j.methods() method, 58 * returns error, data via callback. 59 */ 60Meteor.neo4j.call('GetAllUsers', null, function(error, data){ 61 Session.set('AllUsers', data.users); 62});
var N4JDB;
1/* 2 * Server only 3 * @description Current GraphDatabase connection object, basically created from 'new Neo4j()'' 4 */ 5Meteor.N4JDB; 6 7 8/* You may run queries with no returns on server with it: */ 9Meteor.N4JDB.query('CREATE (a:User {_id: ”123”})'); 10 11 12/* To set listener: */ 13Meteor.N4JDB.listen(function(query, opts){ 14 console.log('Incoming query: ' + query, opts); 15});