How to Copy Sub-Graph in Neo4j using Cypher - neo4j

I am trying to simulate a file system using Neo4j, Cypher, and Python(Py2Neo).
I have created the data model as shown in the following screenshot.
Type=0 means folder and type=1 means file.
.
.
I am implementing functions like Copy, Move etc for files/folders.
Move functions look simple, I can create a new relationship and delete the old one. But copying files/folders need to copy the sub-graph.
How can I copy the sub-graph?
I am creating a python module so trying to avoid apoc.

Even though you're trying to avoid APOC, it already has this feature implemented in the most recent release: apoc.refactor.cloneSubgraph()
For a non-APOC approach you'll need to accomplish the following:
MATCH to distinct nodes and relationships that make up the subgraph you want to clone. Having a separate list for each will make this easier to process.
Clone the nodes, and get a way to map from the original node to the cloned node.
Process the relationships, finding the start and end nodes, and following the mapping to the cloned nodes, then create the same relationship type using the cloned nodes for your start and end nodes of the relationship, then copy properties from the original relationship. This way you don't have any relationships to the originals, just the clones.
Determine which nodes you want to reanchor (you probably don't want to clone the original), and for any relationship that goes to/from this node, create it (via step 3) to the node you want to use as the new anchor (for example, the new :File which should be the parent of the cloned directory tree).
All this is tough to do in Cypher (steps 3 and 4 in particular), thus the reason all this was encapsulated in apoc.refactor.cloneSubgraph().

Related

py2neo (Neo4j) bulk operation

I have created a nice graph using Neo4j Desktop, using a local CSV file that I added to the project. now I'm trying to use python to do that automatically for that I'm trying to use methods from here https://py2neo.org/2021.1/bulk/index.html like create/merge nodes/relatioships.
I have 2 questions,
Do I need to use create method (create node for exmaple) and after that to use merge method (merge nodes for this example) or can use merge nodes from the begining?
I have tried to use merge only and I got some wierd things when I'm using large sample size.
2)After creation of nodes and relationships how can I change the visualization of the nodes (put some value in the node)?
*If there is an other way to use python to create graph from a big CSV file I would like to hear, Thanks!

Does Apache Sling have symbolic links for nodes?

I'd like to normalize my repository. I've got a bunch of identical nodes - identical properties and identical child nodes with their identical properties. I'd like to have just one node that defines the properties and children and have the rest just reference it, thereby eliminating a bunch of redundant nodes.
Is there some property that I can add to a node to make it a duplicate of another without having to actually copy it, like a Unix symbolic link?
Have you looked at the x-ref component? It creates a node that points to the original node & renders the original node instead.

How to duplicate a node and set values on the original in Cypher

I'm creating a very basic versioning system for my nodes in my database. What I want to do is when there is an edit:
Replicate node
Update the node
Link (oldreplica)-[:IsPreviousVersionOf]->(replica)
Delete (oldreplica)-[:IsPreviousVersionOf]->(node)
Link (replica)-[:IsPreviousVersionOf]->(node)
Increment the version number on the node
This way I don't have to touch any of the relationships the node has. Every query I write ends up with the node and replica having the same content.
Is there a way to do this, or do I need to write two queries?
You can do this all in one query; I think the two pieces you're missing are how to copy the node in the first place, and how to "join" subqueries using the WITH keyword. Here's an example. You should triple-check this query, because your terminology and relationship shifting is tricky, so please verify carefully this is what you want.
The WITH blocks here bind certain matched nodes to variables which you can use in subsequent queries. In this way we can carry over the results of one query into another. The other bit is that nodes are just maps of their properties, so you can "copy" a node by setting one map to another.
MATCH (node:Content{version:1})
WITH node as oldNode
CREATE (copy:Cotent)
SET copy=oldNode
WITH oldNode, copy
MATCH (oldreplica:Content{version:0})
MERGE (oldNode)-[:IsPreviousVersionOf]->(copy)
MERGE (oldreplica)-[oldRel:IsPreviousVersionOf]->(copy)
DELETE oldRel
WITH copy, oldNode
MERGE (copy)-[:IsPreviousVersionOf]->(oldNode)
MERGE (oldreplica)-[:IsPreviousVersionOf]->(copy);
Okay, I've figured it out!
// Find the editable Node
MATCH (mainNode)-[:HasInternal]->(:EditableUuid{uuid:'2828b80b-e3d8-478e-ad31-b791b4e8d318'})
// Create a copy and copy the contents
CREATE (copy:Content)
SET copy = mainNode
// Create a new subquery so that we don't set the contents of both copy and mainNode
WITH mainNode, copy
// Increment the version number on the mainNode
SET mainNode.version = mainNode.version + 1
// Connect replica to the mainNode
MERGE (copy)-[:IsPreviousVersionOf]->(mainNode)
// Create a new subquery where we change the links of any old versions
with mainNode, copy, copy.version - 1 as oldversion
// Find older versions and connect them to the copy
MATCH (oldreplica:Content{version:oldversion})-[oldRel:IsPreviousVersionOf]->(mainNode)
MERGE (oldreplica)-[:IsPreviousVersionOf]->(copy)
// Delete the old relationship of the nodes
DELETE oldRel
This way the 'newest' version is always the one that already has the links and the old ones are just copies of that one in time.

neo4j - how to snapshot everything in a label

Im using neo4j to store information about maps and sensors. Every time the map or sensor layout changes I need to keep a copy. I can imagine querying and manually creating said copy but I'm wondering if it's possible to build a neo4j type query that would do this for me.
So far all I've come up with is a way to replicate the nodes in a given label:
match ( a:some_label { some_params }) with a create ( b:some_label ) set b=a,b.other_id=value;
This would allow me to put version and time stamp info on a given snap shot.
What it doesn't do is copy the edge information. Suggestions? Maybe a second (similar) query?
If I understand you correctly, you are essentially trying to maintain a history of the state of a node and the state of its incoming relationship. One way to do this is to chain the nodes in reverse chronological order.
For example, suppose the nodes in the chain are labeled Some_label and the relationships are of type SOME_TYPE. The head node of the chain is always the current (most recent) node. Unless a Some_label node is chronologically the earliest node in the chain, it will have a SOME_TYPE relationship to the previous version of the node.
Here is how you'd insert a new relationship and node (with some properties) at the head of the chain. (Just to set up this example, I assume that the first node in the chain is linked to by some node labeled HeadRef).
MATCH (x:HeadRef)-[r1:SOME_TYPE]->(a1:Some_label)
CREATE (x)-[r2:SOME_TYPE {x: "ghi"}]->(a2:Some_label {a:123, b: true})-[r:SOME_TYPE]->(a1)
SET r=r1
WITH r1
DELETE r1
Note that this approach is also much more performant than maintaining your own other_id property to link nodes together. You should always use relationships instead -- that is the graph DB way.

How to create a node with id 0?

I deleted the reference node. So I need to recreate the reference node.
Using cypher how to create a node with id 0?
thanks.
The short answer is you can't, and you don't need to. Do you have a specific problem without that node? If so, maybe you can elaborate, chances are there is something else that answers your problem better than trying to recreate a node with a specific id.
The long answer is you can't assign id:s to nodes with cypher. The id is an index or offset into the node storage on disk, so it makes sense to let Neo4j worry about it and not try to manipulate it or include it in any application logic. See Node identifiers in neo4j and Has anyone used Neo4j node IDs as foreign keys to other databases for large property sets?.
You also most likely don't need a reference node. It is created by default in a new database, but it's use is deprecated and it won't exist in future releases. See Is concept of reference node in neo4j still used or deprecated?.
If you still want to assign id to nodes you create, it is accidentally possible in a roundabout way with with the CSV batch importer (1,2) and, I believe, with the Java API batch inserter.
If you still want to recreate or simulate the reference node you can either delete the database data files and let Neo4j recreate the the database, or you can try what this person did: Recreate reference node in a Neo4j database. You can also force Neo4j to recycle the ids of deleted nodes faster, so that new nodes that you create receive those ids that have been freed up and not yet reassigned.

Resources