Reputation: 862
I have multiple relationships that stem from a node. Each of these relationships are of the same label. The relationships point to a child node (not neccesarily unique). After I fetch all child nodes that link to the parent by this relationship label, I order them by a relationship property called trueindex. I then have an array of nodes that my client can iterate through in the correct sort order.
The problem comes when I try to "push, pop, unshift, etc..." onto this array. If I want to add a new relationship to the front of the order, I have to create a new relationship, use it to link the parent to the child node, then add a 0 value to the relationships trueindex property. The problem is that there already is a relationship with a trueindex value of zero and I need to perform somesort of casecading function that increments the trueindex of all other relationships (of the same type that all stem from that same parent node). I am trying to find a way to get this "array-like" index number functionality for free
The only way I can think to do so is to first delete all relationships of that particular label that stem from the parent. And then rewrite the entire array (with all the prexisting relationship that increment their trueindex by one) in order to reflect the correct order. This is fine for small cases but if I plan for a parent node to have a significant amount of relationships, then its a problem to rewrite the entire array (set of relationships) every time I want to add, remove by index, pop, etc and yet still maintain an order of relationships that stem from the parent node.
Does Neo4j have some sort of relationship feature to write to the correct order when creating new relationships?
I am very grateful for advise you can offer.
Upvotes: 2
Views: 931
Reputation: 29436
You can use SET
to increment or decrement properties of existing relations first.
The following example shifts trueIndex
of existing relations and pushes a new relation (to an existing child node) at index 0:
MATCH (n:Root)-[r:HAS]->(c:Child)
WHERE id(n) = 0
SET r.trueIndex = r.trueIndex + 1
WITH n, min(r.trueIndex) as indexStart, max(r.trueIndex) as indexEnd
CREATE (n)-[r:HAS {trueIndex:(indexStart-1)}]->(c:Child)
WHERE id(c) = 12
RETURN n,r,c
You can modify the query according to your needs.
Design wise, I agree with @jjaderberg 's answer, it would be simpler to keep a linked list to represent an array.
Upvotes: 1
Reputation: 9952
Try keeping the child nodes in linked lists. The structure will look something like
(p:Parent)-[r1:CHILDREN]->(c1:Child)-[r2:NEXT]->(c2:Child)-[r3:NEXT]->(c3:Child)
This maintains the order of your child nodes and allows you to improve your interaction with the structure in two ways:
Inserting a new node into this structure only involves changes to the relationships 'before' and 'after' the place that node is going, as opposed to the entire structure. For example, to insert newc
between c1
and c2
, you delete r2
, create newc
and create :NEXT
relationships from c1
to newc
to c2
. Analogous for other operations: all your alterations are now local within the structure.
You use relationships and their types to structure your data, instead of relationship properties. This is more flexible and almost always more performant (sometimes much more performant).
To read a single child from this structure you now use your trueindex
to declare the depth in the linked list at which to find the node, i.e.
MATCH (parent:Parent {parentId: 1234})-[:CHILDREN]->()-[:NEXT*3]->(child)
RETURN child
and to retrieve a parent with all its children
MATCH (parent:Parent {parentId: 1234})-[:CHILDREN|NEXT*]->(child)
RETURN parent, COLLECT(child) as children
Upvotes: 2