!Please always remove autopublish
package before using this package!
- About
- Example Application
- Installation
- Notes
- API
- More about reactive data
- Usage examples
- Test on your Dev stage
- Get deeper to understanding the package
Neo4jreactivity creates reactive and isomorphic layer between Neo4j and your Meteor based application. All write requests is synchronized between all clients. Please see this package on atmospherejs.com.
The basic example is build on top of --example leaderboard
- the Meteor's Neo4j-based Leaderboard App
meteor add ostrio:neo4jreactivity
If you have many different queries to Neo4j database on production environment, you will probably want to avoid Neo4jCache
collection overwhelming. Make build-in JavaScript-based TTL utility is useless, so we are suggest to take a look on TTL indexes and expire data tutorial. Neo4jCache
records has created
{Date} field, so in our case it will be something like:
/* run this at mongodb shell */
db.Neo4jCache.createIndex({
created: 1
},{
expireAfterSeconds: 3600 * 24 /* 3600 * 24 = 1 day */
});
In documentation below you will find two different approaches how to send queries and retrieve data to/from Neo4j database. It is methods
/calls
and collection
/publish
/subscription
.
It is okay to combine them both. Most advanced way is to use methods
/calls
, - using this approach allows to you send and retrieve data directly to/from Neo4j database, our driver will only hold reactive updates on all clients.
But at the same moment collection
/publish
/subscription
approach has latency compensation and let to work with data and requests as with minimongo instance, but limited to simple insert
/update
/remove
operations on data sets, so you can't set relations, indexes, predicates and other Cypher query options (Labels and Properties is well supported. For Labels use __labels
property as {__labels: ":First:Second:Third"}
).
Meteor.neo4j.allowClientQuery
allowClientQuery
{Boolean} - Allow/Deny Cypher queries execution on the client side
Meteor.neo4j.connectionURL = 'http://user:pass@localhost:7474';
- Set connection URL, uncluding login and password to Neo4j DataBase
- Example
Meteor.neo4j.rules.write
- Array of strings with Cypher write operatorsMeteor.neo4j.rules.read
- Array of strings with Cypher read operatorsMeteor.neo4j.set.allow([rules])
- Set allowed Cypher operators for client side
rules
{[String]} - Array of Cyphper query operators Strings
Meteor.neo4j.set.deny([rules])
- Set denied Cypher operators for client side
rules
{[String]} - Array of Cyphper query operators Strings- For example to deny all write queries, use:
Meteor.neo4j.set.deny(Meteor.neo4j.rules.write)
- Example
Meteor.neo4j.query(query, opts, callback)
- Returns reactive {Object} withget()
method.
query
{String} - Name of publish function. Please use same name in collection/publish/subscriptionopts
{Object} - A map of parameters for the Cypher query.callback
{Function} - Callback which runs after each subscriptionerror
{Object|null} - Error of Neo4j Cypher query execution or nulldata
{Object|null} - Data or null from Neo4j Cypher query execution
- Example
Meteor.neo4j.collection(name)
name
{String} - Name of collection.
users = Meteor.neo4j.collection 'Users'
- This method returns collection with next methods:
publish(name, func, [onSubscribe])
[Server] - Publish dataset to client.name
{String} - Publish/Subscription namefunc
{Function} - Function which returns Cypher queryonSubscibe
{Function} - Callback function called right after data is published- Example
users.publish 'currentUser', () -> return 'MATCH (user:User {_id: {_id}}) RETURN user;'
subscribe(name, [opts], link)
[Client] - Subscribe on dataset.name
{String} - Publish/Subscription nameopts
{Object|null} - A map of parameters for the Cypher querylink
{String} - Sub object name, to link as MobgoDB row(s). See example below:- Example
users.subscribe 'currentUser', _id: Meteor.userId(), 'user'
find([selector], [options])
- Example. Use to search thru returned data from Neo4jfetch()
- Use to fetch Cursor data
findOne([selector], [options])
insert(doc, [callback])
- Exampleupdate(selector, modifier, [options], [callback])
- Exampleupsert(selector, modifier, [options], [callback])
remove(selector, [callback])
- Example- Note: All
selector
s anddoc
support__labels
property, - use it to set Cypher label on insert or searching data, see this example - Collection() example
Meteor.neo4j.call(name, [[opts], [link].. ], callback)
- Call server Neo4j method Call for method registered viaMeteor.neo4j.methods
.
name
{String} - Name of method functionopts
{Object} - A map of parameters for the Cypher query.callback
{Function} - Returnserror
anddata
arguments.- Returns {Object} - With
cursor
and reactiveget()
method - Example
Meteor.neo4j.methods(object)
- Create server Cypher queries
object
{Object} - Object of method functions, which returns Cypher query string- Example
Meteor.neo4j.publish(collectionName, name, func, [onSubscribe])
collectionName
{String} - Collection name of method functionname
{String} - Name of publish function. Please use same name in publish/subscriptionfunc
{Function} - Function wich returns Cypher query stringonSubscribe
{Function} - Callback which runs after each subscription- Example
Meteor.neo4j.subscribe(collectionName, name, [opts], [link])
collectionName
{String} - Collection name of method functionname
{String} - Name of subscribe function. Please use same name in publish/subscriptionopts
{Object} - A map of parameters for the Cypher query.link
{String} - Sub object name, to link as MobgoDB row(s)- Example
- Note: Wrap
Meteor.neo4j.subscribe()
intoTracker.autorun()
- 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
-
Deny: None
-
Write:
CREATE
SET
DELETE
REMOVE
INDEX
DROP
MERGE
Note: This is very important to use same node's link names for same node types in all Cypher queries, cause the way Neo4jReactivity subscribes on data. For example if we would like to retrieve Users from Neo4j and update them later, so data will be updated reactively:
MATCH (usr {type: 'User'}) RETURN usr
# To update use only `usr` alias for node:
MATCH (usr {type: 'User', perms: 'guest'}) SET usr.something = 2
Of course Neo4jReactivity knows about Neo4j labels and use them for subscription too. With labels you may use different node's name aliases, but it's not recommended:
# To retrieve
MATCH (a:User) RETURN a
# To update:
MATCH (b:User {perms: 'guest'}) SET b.something = 2
It will work, but much better if you will use:
# To retrieve
MATCH (user:User) RETURN user
# To update:
MATCH (user:User {perms: 'guest'}) SET user.something = 2
friends = Meteor.neo4j.collection 'friends'
friends.publish 'allFriends', () ->
return "MATCH (user {_id: {userId}})-[:FriendOf]->(friends) RETURN friends"
friends.subscribe 'allFriends', {userId: Meteor.userId()}, 'friends'
Template.friendsNamesList.helpers
friends: ()->
friends.find({})
<template name="friendsNamesList">
<ul>
{{#each friends}}
<li>{{name}}</li>
{{/each}}
</ul>
</template>
#CoffeeScript
Meteor.neo4j.methods
getUsersFriends: () ->
return "MATCH (user {_id: {userId}})-[:FriendOf]->(friends) RETURN friends"
#CoffeeScript
Template.friendsNamesList.helpers
userFriends: () ->
Meteor.neo4j.call 'getUsersFriends', {userId: Meteor.userId()}, (error, data) ->
throw new Meteor.error '500', 'Something goes wrong here', error.toString() if error
else
Session.set 'currenUserFriends', data
return Session.get 'currentUserFriens'
<template name="friendsNamesList">
<ul>
{{#each userFriends.friends}}
<li>{{name}}</li>
{{/each}}
</ul>
</template>
By default query execution is allowed only on server, but for development purpose (or any other), you may enable it on client:
#Write this line in /lib/ directory to execute this code on both client and server side
Meteor.neo4j.allowClientQuery = true
#Do not forget about minimum security, deny all write queries
Meteor.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'])
#CoffeeScript
Meteor.neo4j.set.allow ['create', 'Remove']
Meteor.neo4j.set.deny ['SKIP', 'LIMIT']
#OR to allow or deny all
Meteor.neo4j.set.allow '*'
Meteor.neo4j.set.deny '*'
#To deny all write operators
Meteor.neo4j.set.deny Meteor.neo4j.rules.write
#default rules
Meteor.neo4j.rules =
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']
deny: []
#Write this line in /lib/ directory to execute this code on both client and server side
Meteor.neo4j.allowClientQuery = true
#Client code
getAllUsers = ->
return Meteor.neo4j.query('MATCH (a:User) RETURN a').get();
For more info see: neo4jdriver and node-neo4j
Code licensed under Apache v. 2.0: node-neo4j License
- 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
After installing ostrio:neo4jreactivity
package - you will have next variables:
Meteor.Neo4j;
- [Server] GraphDatabase object from node-neo4j npm package. Use to connect to other Neo4j servers.Meteor.N4JDB;
- [Server] GraphDatabase instance connected to Neo4j server. Use to run Cypher queries directly in Neo4j DB, without any reactivityMeteor.neo4j;
- [Isomorphic] Neo4jReactivity Driver object
/*
* Server only
* @class
* @name Neo4j
* @param url {string} - URL to Neo4j database
* Note: It’s better to store URL in environment
* variable, 'NEO4J_URL' or 'GRAPHENEDB_URL' -
* so it will be automatically picked up by our driver
*
* @description Run it to create connection to database
*/
Meteor.N4JDB = new Meteor.Neo4j(/* URL TO SERVER */);
Newly created object has next functions, you will use:
/* @name query */
Meteor.N4JDB.query('MATCH (n:User) RETURN n', null /* A map of parameters for the Cypher query */, function(err, data){
Session.set('allUsers', data);
});
/* @name listen */
Meteor.N4JDB.listen(function(query, opts){
console.log('Incoming request to neo4j database detected!');
});
/* Both (Client and Server)
* @object
* @name neo4j
* @description Application wide object neo4j
*/
Meteor.neo4j;
Meteor.neo4j.allowClientQuery = true; /* Allow/deny client query executions */
Meteor.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:
/* @namespace Meteor.neo4j.set
* @name allow
* @param rules {array} - Array of Cypher operators to be allowed in app
*/
Meteor.neo4j.set.allow(rules /* array of strings */);
/* @namespace Meteor.neo4j.set
* @name deny
* @param rules {array} - Array of Cypher operators to be forbidden in app
*/
Meteor.neo4j.set.deny(rules /* array of strings */);
/*
* @function
* @namespace neo4j
* @name query
* @param query {string} - Cypher query
* @param opts {object} - A map of parameters for the Cypher query
* @param callback {function} - Callback function(error, data){...}. Where is data is [REACTIVE DATA SOURCE]
* So to get data for query like:
* 'MATCH (a:User) RETURN a', you will need to:
* data.a
* @param settings {object} - {returnCursor: boolean} if set to true, returns Mongo\Cursor
* @description Isomorphic Cypher query call
* @returns Mongo\Cursor or ReactiveVar [REACTIVE DATA SOURCE]
*
* @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
*
*/
allUsers = Meteor.neo4j.query('MATCH (users:User) RETURN users');
var users = allUsers.get().users;
/* or via callback, on callback there is no need to run `get()` method */
var users;
Meteor.neo4j.query('MATCH (users:User) RETURN users', null, function(error, data){
users = data.users;
});
/*
* Server only
* @name methods
* @param methods {object} - Object of methods, like: { methodName: function(){ return 'MATCH (a:User {name: {userName}}) RETURN a' } }
* @description Create server methods to send query to neo4j database
*/
Meteor.neo4j.methods({
'GetAllUsers': function(){
return 'MATCH (users:User) RETURN users';
}
});
/*
* Client only
* @name call
* @description Call for server method registered via neo4j.methods() method,
* returns error, data via callback.
*/
Meteor.neo4j.call('GetAllUsers', null, function(error, data){
Session.set('AllUsers', data.users);
});
/*
* Server only
* @description Current GraphDatabase connection object, basically created from 'new Neo4j()''
*/
Meteor.N4JDB;
/* You may run queries with no returns on server with it: */
Meteor.N4JDB.query('CREATE (a:User {_id: ”123”})');
/* To set listener: */
Meteor.N4JDB.listen(function(query, opts){
console.log('Incoming query: ' + query, opts);
});