Iterate through collection with index in Cypher - neo4j

Say I have matched a collection of relationships:
MATCH a-[r:BELONGS_TO]->b
How can I iterate through each relationship and assign it an index? In pseudocode:
for i in range(0, # of r's)
r.order = i

This should work:
MATCH (a)-[r:BELONGS_TO]->(b)
WITH collect(r) as rels
WITH rels, range(0, size(rels)) AS is
UNWIND is AS i
WITH rels[i] as rel, i
SET rel.order = i

You can hack it a bit :
MATCH (a)-[r:BELONGS_TO]->(b)
WITH collect(r) as relationships
UNWIND range(0, size(relationships)-1) as x
RETURN relationships[x]

Depending on your requirements, you may be able to use the "internal" ID that the neo4j DB automatically assigns to every relationship (and node). Although every internal ID is unique, after a relationship (or node) is deleted, its internal ID can be reused by a new relationship (or node). Over time, the set of active internal IDs for relationships (and nodes) may no longer have a 0 origin and may not have contiguous integer values.
If the internal ID is adequate for your needs, then there is no need to add your own id or index property.
You can use the ID() function to get the internal ID whenever you need it. For example, this is how you'd get the internal ID of every BELONGS_TO relationship:
MATCH ()-[r:BELONGS_TO]->()
RETURN ID(r);

Related

Is matching with id performant in Neo4J?

I'm wondering, when I have read the data of a node and I want to match it in another query, which way will have the best performance? Using id like this:
MATCH (n) WHERE ID(n) = 1234
or using indices of the node:
MATCH (n:Label {SomeIndexProperty: 3456})
Which one is better?
IDs are a technical ID for Neo4j, and those should not be used as a primary key for your application.
Every node (and relationship) has a technical ID, and it's stable over time.
But if you delete a node, for example the node 32, Neo4j will reuse this ID for a new node.
So you can use it in your queries inside the same transaction (there is no problem), otherwise you should know what you are doing.
The only way to retrieve the technical ID, is to use the function ID like you do on your first query : MATCH (n) WHERE ID(n) = 1234 RETURN n.
The ID is not exposed as a node's property, so you can't do MATCH (n {ID:1234}) RETURN n.
You have noticed that if you want to do a WHERE on a strict equality, you can do put the condition directly on the node.
For example :
MATCH (n:Node) WHERE n.name = 'logisima' RETURN n
MATCH (n:Node {name:'logisima'}) RETURN n
Those two queries are identicals, they generate the same query plan, it's just a syntactic sugar.
Is it faster to retrieve a node by its ID or by an indexed property ?
The easier way to know the answer to this question is to profile the two queries.
On the one based on the ID, you will see the box NodeByIdSeek that cost 1 db hit, and on the one with a unique constrainst you will see the box NodeUniqueIndexSeek with 2 db hits.
So searching a node by its ID is faster.

Duplicate object in a list when I try to map all related entities

According to this post I tried to map all related entities in a list.
I used the same query into the post with a condition to return a list of User but it returns duplicate object
MATCH (user:User) WHERE <complex conditions>
WITH user, calculatedValue
MATCH p=(user)-[r*0..1]-() RETURN user, calculatedValue, nodes(p), rels(p)
Is it a bug? I'm using SDN 4.2.4.RELEASE with neo4j 3.2.1
Not a bug.
Keep in mind a MATCH in Neo4j will find all occurrences of a given pattern. Let's look at your last MATCH:
MATCH p=(user)-[r*0..1]-()
Because you have a variable match of *0..1, this will always return at least one row with just the user itself (with rels(p) empty and nodes(p) containing only the user), and then you'll get a row for every connected node (user will always be present on that row, and in the nodes(p) collection, along with the other connected node).
In the end, when you have a single user node and n directly connected nodes, you will get n + 1 rows. You can run the query in the Neo4j browser, looking at the table results, to confirm.
A better match might be something like:
...
OPTIONAL MATCH (user)-[r]-(b)
RETURN user, calculatedValue, collect(r) as rels, collect(b) as connectedNodes
Because we aggregate on all relationships and connected nodes (rather than just the relationships and nodes for each path), you'll get a single row result per user node.

How to update existing relationship in neo4j?

I have two nodes A and B.
They have a relationship R, with some property P, on this relationship.
How I can update this relationship R, with a new value for P?
I tried merge, but this creates a new relationship, but I want to update the existing one.
Match on your nodes and the relationship, then use SET to update the relationship property. For example:
MATCH (a {name:"A"})-[r]-(b {name:"B"})
SET r.P = "bar"
It's generally best, when looking up specific nodes, to use labels in the query, and have an index or unique constraint (whichever makes the most sense) to speed up your lookups.
Match (a:A), (b:B) Merge (a)-[r:YourRelations]->(b) Set r.P="new Prop" Return r

Auto-generation of id in Neo4j

Will Neo4j auto-generate unique ids for all the nodes created using 'CREATE' query, as 'id' in Mysql? We created a node with
CREATE (n: user{name:"x", age:10}) return n
If we want to update 'name' property, how to do it in Neo4j?
From the documentation though,
Searching for nodes by id can be done with the id() function in a predicate.
Neo4j reuses its internal ids when nodes and relationships are deleted. This means that applications using, and relying on internal Neo4j ids, are brittle or at risk of making mistakes. It is therefor recommended to rather use application generated ids.
It is a good idea to as they say, use Application generated ids that are stored as properties of the node. You need to set the application generated id while creating the node and then use that key on merge statements
MERGE (n:user{key:<myApplicationKey>}) return n
SET n.name="x", age=10
There is an internal id, you can access it the id() function
CREATE (n:User {name="x", age: 10}) RETURN n, id(n) as nodeId
Later on, you can update it with
MATCH (n) WHERE id(n) = 12345 SET n.name = "y"

How retrieve all nodes linked by a relationship

I am using neo4j, I have nodes with two properties: name and id. I have an index on id.
I have relationships "CALL" with a property: "by_test". This property can take different value (id of any node).
Two nodes can have multiple CALL relationships with different by_test property value.
So let's say I have 1..N nodes linked by the same CALL.by_test property value.
Node1 -> Node2 -> Node3 -> .. -> Node N
How can I get all these nodes?
Do I need to put an Index on the relationship?
Do I have to create dynamic relationship? Instead of CALL.by_test=value, use value has a relationship.
Thanks!
Using Cypher, you could query for that list like this:
START n=node:node_auto_index(name="one")
MATCH p=(n)-[r:CALL*1..]->(m)
WHERE ALL(x in r WHERE x.by_test = 3)
RETURN n,m
In the MATCH you bind a term r to the CALL relationships, which you then use in the WHERE clause to check the by_test property of each.
As Michael Hunger noted, the r is a collection of relationships, so the WHERE needs to use ALL to check each of the relationships.

Resources