Enforcing the non-existence of relationships in Neo4j - neo4j

In Neo4j, is there a way of enforcing that a node of a label X is not connected to a node of label Y?
For example, if someone tried to run a query such as:
MERGE (:X)-[:SOME_RELATIONSHIP]->(:Y)
would there be a way to guarantee that such a query would fail?
Thank you!

Neo4j's constraints don't currently support relationship existence or restriction, so you'd need to put in some extra work.
If you have APOC Procedures, you could register a trigger which could get evaluated to check if a relationship being created connects two nodes of those labels and use apoc.util.validate() to generate an error which will fail and rollback the transaction.
If you want to do this without APOC, it's a bit more work, as you'll need to create a TransactionEventHandler, and then a kernel extension to load your event handler. Here's a blog entry on this approach.

Related

Neo4j - is it possible to visualise a simple overview of my database?

I've got my graph database, populated with nodes, relationships, properties etc. I'd like to see an overview of how the whole database is connected, each relationship to each node, properties of a node etc.
I don't mean view each individual node, but rather something like an ERD from a relational database, something like this, with the node labels. Is this possible?
You can use the metadata by running the command call db.schema().
In Neo4j v4 call db.schema() is deprecated, you can now use call db.schema.visualization()
As far as I know, there is no straight-forward way to get a nicely pictured diagram of a neo4j database structure.
There is a pre-defined query in the neo4j browser which finds all node types and their relationships. However, it traverses the complete graph and may fail due to memory errors if you have to much data.
Also, there is neoprofiler. It's a tool which claims to so what you ask. I never tried and it didn't get too many updates lately. Still worth a try: https://github.com/moxious/neoprofiler
Even though this is not a graphical representation, this query will give you an idea on what type of nodes are connected to other nodes with what type of relationship.
MATCH (n)
OPTIONAL MATCH (n)-[r]->(x)
WITH DISTINCT {l1: labels(n), r: type(r), l2: labels(x)}
AS `first degree connection`
RETURN `first degree connection`;
You could use this query to then unwind the labels to write that next cypher query dynamically (via a scripting language and using the REST API) and then paste that query back into the neo4j browser to get an example set of the data.
But this should be good enough to get an overview of your graph. Expand from here.

Add a relationship without data already in the database

It appears that I can't add a relationship unless there is already some data in some Entities that obey that relationship. Is this correct? I want to be able to set up my relationships and Labels first and then populate with data and have the data just use the relationships.
I am using:
MATCH (from:this_label),(to:that_label)
WHERE from.id = to.uuid
CREATE (from)-[:hasARelationship]->(to);
Basically, I want to be able to define a bunch of relationships on nodes of a certain label, even if those node-type do not yet exist. And then when some data of those nodes comes into the database it will hook up the relationships automatically.
It may be helpful to distinguish between the responsibilities of enforcing a constraint and fulfilling a constraint.
Neo4j allows for indices and constraints associated with labels. Indices and constraints created for a label are used to index and constrain the nodes that have that label. As of version 2.2.5, there is only one type of constraint: a uniqueness constraint for a single property. There have been talk about adding constraints for combinations of properties, and for relationships, but I don't know the status of these conversations.
The Neo4j schema constraints enforce something, but they will not fulfill, in the sense of changing your operations on the database to satisfy the constraint. If there were constraints enforcing that a node with label A may only be created if it has a relationship of type R to a node with label B, they would block your operation if it did not satisfy the constraint, but they would not satisfy it for you.
The best way to achieve this is a) to satisfy this requirement in your client application, or b) to create an extension for Neo4j. For an extension example, consider neo4j-uuid by Stefan Armbruster. It listens to transactions (using what's called a TransactionEventListener) and makes sure that any node that is created in the database has a UUID. This extension satisfies what could only be enforced by a corresponding Neo4j schema constraint (there are other differences, e.g., the constraint would be limited to the scope of a label).
A way to achieve your intention could be to either create an extension which listens to what you write to the database and satisfies your constraint, altering your operations if necessary; or, one which provides an invocation target in the server (a RESTful endpoint) that you can invoke whenever you want to create a node with a particular label. The extension would then create the node and other elements necessary to fulfill your schema. A downside to the former could be the overhead of listening to all your operations, a downside to the latter could be that it breaks your flow of interaction with the database to introduce a separate type of invocation (e.g., if you normally execute cypher statements and have to pause to issue a separate POST request and interpret the response before continuing).
If I understand you correctly, you want to use MERGE instead of MATCH.
MERGE (from:this_label) -[:hasARelationship]-> (to:that_label) WHERE from.id = to.uuid
If you are trying to create relationships without nodes, I guess that is not even possible in NEO4J. Infact, it wouldn't be possible in any graph in general.
It does not make sense to pre-populate your DB with relationships that connect to dummy nodes. Among the many reasons are these:
You would not be able to make any meaningful queries involving such relationships
Trying to fill in the dummy nodes later on with actual data may be a complex endeavor
It is very easy to created relationships right when they are needed. neo4j is a "schemaless" DB (except when you define uniqueness constraints, as #jjaderberg mentions). You can create a relationship of any type connecting nodes with any labels (or no labels) at any time. To keep things organized, you may choose to write your DB client code and Cypher queries to conform to your own conceptual "schema", but neo4j has no such a requirement.

Is there a race condition when creating unique paths?

I recently discovered that a race condition exists when executing concurrent MERGE statements. Specifically, duplicate nodes can be created in the scenario where a node is created after the MATCH step but before the CREATE step of a given MERGE.
This can be worked around in some instances using unique constraints on the merged nodes; however, this falls short in scenarios where:
There is no single unique property to enforce (e.g. pairs of properties need to be unique but individual ones don't).
Trying to merge relationships and paths.
Does using CREATE UNIQUE solve this problem (or do the same pitfalls exist)? If so, is it the only option? It feels like the usefulness of MERGE is fairly heavily diminished when it effectively can't guarantee the uniqueness of the path or node being merged...
When MERGE statements are executed concurrently, these situations may occur. Basically, each transaction gets a view of the graph at the first point of reading, and won't see updates made after that point (with some variations). The main exception to this are uniquely constrained nodes, where Neo4j will initialise a fresh reader from the index when reading, regardless of what was previously read in the transaction.
A workaround could be to create a 'dummy' property and a unique constraint on it and one of the node labels. In Neo4j 2.2.5, this should work to get around your problem.

How to programmatically add constraints to Neo4J Cypher queries

I am writing a sever plugin for Neo4J. The plugin receives a cypher query, and executes it. Currently, my implementation uses a CypherExecutor.
I now need to further constrain the results. (For example, imagine that the results need to be filtered by ACLs.)
One approach is to filter the results after executing the query. I'd rather not do this, for performance reasons as well as other limitations (for example, any aggregate results would be wrong.)
I considered adding the constraints to the query itself. I've looked at the command.AbstractQuery subclasses produced using the CypherParser. That object model is immutable.
I am wondering whether I will need to resort to cloning Neo4J's ExecutionEngine and CypherCompiler, just to extend the ExecutionPlanBuilder... I would like to avoid this option if at all possible.
Any recommendations about how this can be done?
In my case, I am simply trying to simulate multiple isolated graphs. I am OK with how this might be modeled -- whether I add a 'tenantId' to each node, or maintain a tenant node and add (:Tenant)<-[:scopedTo]-(n) relationships to every node.

Delete all relations and connected nodes in Neo4j for a user

We have selected neo4j as the DB for our web application. The user has a large number of relations and connected nodes. As of now there are about 20 relations for a user. One of the features is a newsfeed feature. If i want to delete a user completely, is the cypher query the best way to delete or is there any other alternative?
Since we are still planning to add new features, the relationships and nodes connected to the user also will increase. So if we use cypher query, the query has to be modified for every new relationship added. Please advise.
Thanks,
Pavan
Yes, you can use Cypher to remove a user. Of course, there are alternative methods, depending on the language or framework you're using with your web application. If you like to have advise on that, please specifiy how you're using Neo4j in detail.
Note that you have to remove all relationships (outgoing and incoming) first in order to be able to remove the node.
Example:
START n = node(3)
MATCH n-[r]-()
DELETE n, r
This example was taken from the official manual: http://docs.neo4j.org/chunked/milestone/query-delete.html
As of Neo4j 2.3 there is another way to do this:
MATCH (n { name:'Andres' })
DETACH DELETE n
I found this example in the documentation at: http://neo4j.com/docs/stable/query-delete.html
An alternative could be to write a gremlin script that traverses your graph starting with your user and is putting in two collection the relationships and the nodes that you intend to delete. If you want to delete everything, perhaps you can implement your depth first traversal in Gremlin and delete while traversing.

Resources