Export a (sub)graph to Cypher script and import it again

Oftentimes you want to export a full (or partial) database to a file and import it again without copying the actual database files.
If you want to do the latter, use neo4j-admin dump/load.

Here are two ways on how to create a Cypher script file from your database or Cypher statement.

Format

Some notes on the format written from these tools:

  • recreate indexes and constraints
  • simple statements per node (CREATE) / relationship (2x MATCH + CREATE)
  • data creation in batches (by default 40k) surrounded with begin, commit
  • uses existing constraints for node-lookup
  • if no constraint on that label exist, use an artificial constraint + property (UNIQUE IMPORT LABEL.UNIQUE IMPORT ID) where the property value is the node-id, on node creation
  • clean up artificial label + property + constraint at the end in batches

APOC

You can install the APOC procedure library.

And then use the apoc.export.cypher.* procedures to create the export.cypher file from your graph or data.
There is more in the documentation but below are some examples.

NOTE: Please note that you have to enable the capability to write to files first in neo4j.conf.

apoc.export.file.enabled=true

<!-- // exports the whole database incl. indexes as cypher statements to the provided file -->
CALL apoc.export.cypher.all("export.cypher",{})

<!-- // exports given nodes and relationships incl. indexes as cypher statements to the provided file -->
MATCH path = (p1:Person)-[r:KNOWS]->(p:Person)
WITH collect(p1)+collect(p2) as export_nodes, collect(r) as export_rels
CALL apoc.export.cypher.data(export_nodes,export_rels,"export.cypher",{}) 
YIELD file, source, format, nodes, relationships, properties, time
RETURN nodes, relationships, time;

<!-- // exports given graph object incl. indexes as cypher statements to the provided file -->
#### ..
CALL apoc.graph.fromPaths([paths],'export_graph',{}) YIELD graph
CALL apoc.export.cypher.graph(graph,"export.cypher",{}) YIELD time
RETURN time;

<!-- // exports nodes and relationships from the cypher statement incl. indexes as cypher statements to the provided file -->
CALL apoc.export.cypher.query(
"MATCH (p1:Person)-[r:KNOWS]->(p:Person) RETURN *","export.cypher",{});

neo4j-shell tools

Install neo4j-shell-tools into your lib directory.
Enable remote shell in your neo4j.conf with dbms.shell.enabled=true.

Or use ./bin/neo4j-shell -path data/databases/graph.db when your server is not running.

Run the command export-cypher -o export.cypher;

or

export-cypher -o export.cypher MATCH (p1:Person)-[r:KNOWS]->(p:Person) RETURN *;

Import with cypher-shell

If you edit the file to replace begin with :begin and commit with :commit,
then you can import them with cypher-shell too.

export.cypher | sed -e 's/^(begin|commit)/:$1/g' ./bin/cypher-shell -u user -p password

Import with neo4j-shell

You can import files generated by these exports with

./bin/neo4j-shell -file export.cypher

Example for export file

$ export-cypher -r -o test.cypher match (n)-[r]->() return n,r

<!-- // create nodes -->
begin
CREATE (:`UNIQUE IMPORT LABEL` {`UNIQUE IMPORT ID`:0});
CREATE (:`User` {`age`:43, `name`:"User1"});
commit

<!-- // add schema -->
begin
CREATE INDEX ON :`User`(`age`);
CREATE CONSTRAINT ON (node:`User`) ASSERT node.`name` IS UNIQUE;
CREATE CONSTRAINT ON (node:`UNIQUE IMPORT LABEL`) ASSERT node.`UNIQUE IMPORT ID` IS UNIQUE;
commit
schema await

<!-- // create relationships -->
begin
MATCH (n1:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`:0}), (n2:`User`{`name`:"User1"}) CREATE (n1)-[:`KNOWS` {`since`:2011}]->(n2);
commit

<!-- // clean up temporary import keys -->
begin
MATCH (n:`UNIQUE IMPORT LABEL`)  WITH n LIMIT 1000 REMOVE n:`UNIQUE IMPORT LABEL` REMOVE n.`UNIQUE IMPORT ID`;
commit
begin
DROP CONSTRAINT ON (node:`UNIQUE IMPORT LABEL`) ASSERT node.`UNIQUE IMPORT ID` IS UNIQUE;
commit

For the export cypher to not using _id for nodes and relationships matching, does that work if I create a unique node property constraint? (e.g. we have a property in nodes to identify them) Or does it have to be a node key constraint?

Yes, apoc.export.cypher.* will take existing constraints into account and prefer these over node-ids, only if there is no constraint, it will use the node-id as neo4jImportId.
Same for the other export procedures.