Migrating neo4j database content / apoc.import.json not working

66 Views Asked by At

I used to call

call apoc.export.json.all("backup.json",{useTypes:true})

to backup my database content on the one hand and now I'm trying to migrate data to another machine on the other hand by exporting to json first and importing it afterwards.

call apoc.import.json("backup.json")

which should be a valid option according to some neo4j developer. However I run into an exception:

Failed to invoke procedure `apoc.import.json`: Caused by: java.lang.RuntimeException: Missing constraint required for import. Execute this query:
CREATE CONSTRAINT FOR (n:MyLabel01) REQUIRE n.neo4jImportId IS UNIQUE;

Even creating this requirement results in more and more errors of that type.

These error occur when I try to migrate my data from an older neo4j version / apoc version to a newer one, but also when I export from neo4j kernel 5.12.0 enterprise with apoc version 5.12.0 according to return apoc.version() and try to import in a fresh database of the same version where I exported the json.

So I tried to find some workaround and found

CALL apoc.load.json("backup.json") yield value
WHERE value.type = "node"
CALL apoc.create.node(value.labels,value.properties)
yield node return node

but I could not figure out how to import the relashionships too.

  • Is there (a different) standard way of porting database content to another machine?
  • Or is there some option to utilize apoc.load.json("backup.json") and to create nodes and relationships?
1

There are 1 best solutions below

0
Necktschnagge On

Workaround

I wrote a little python script to convert the exported json in to a cypher CREATE instruction. It should create the database content as exported previously.

If the exported json has additional properties that are not treated by this script, it prints at least a list of "errors" which are just these ignored parts of the json input, so that the user can manually check.

import argparse
import json

def main(file_path):
    with open(file_path) as my_file:
        
        data = []
        for line in my_file:
            data.append(json.loads(line))
        
        instruction = 'CREATE\n'
        for json_obj in data:
            if json_obj['type'] == 'node':
                node_id = json_obj['id']
                json_obj.pop('id')
                label_clause = ''
                if 'labels' in json_obj:
                    for label in json_obj['labels']:
                        label_clause = label_clause + ':' + label
                    json_obj.pop('labels')
                property_clause = ''
                if 'properties' in json_obj:
                    property_clause += '{  '
                    for key in json_obj['properties']:
                        property_clause += key
                        if isinstance(json_obj['properties'][key], str):
                            property_clause += " : \""
                            property_clause += json_obj['properties'][key]
                            property_clause += "\", "
                        else:
                            property_clause += " : "
                            property_clause += str(json_obj['properties'][key])
                            property_clause += ", "
                        
                    property_clause = property_clause[:-2]
                    property_clause += '}'
                    json_obj.pop('properties')
                instruction += ' (node_{}{}{}),\n'.format(node_id, label_clause, property_clause)
        for json_obj in data:
            if json_obj['type'] == 'relationship':
                relationship_id = json_obj['id']
                json_obj.pop('id')
                from_id = json_obj['start']['id']
                json_obj.pop('start')
                to_id = json_obj['end']['id']
                json_obj.pop('end')
                
                label_clause = ''
                if 'label' in json_obj:
                    label_clause = ':{}'.format(json_obj['label'])
                    json_obj.pop('label')
                
                relation_clause = 'relationship_{}{}'.format(relationship_id, label_clause)
                
                instruction += ' (node_{})-[{}]->(node_{}),\n'.format(from_id, relation_clause, to_id)
        print('ERRORS:\n') # should print anything from the original json which has been ignored by the code above
        for json_obj in data:
            json_obj.pop('type')
            if bool(json_obj):
                print(json_obj)
                print()
        
        print()
        print()
        print()
        print()
        
        
        instruction = instruction[:-2] + ';\n'
        
        with open("instruction.txt", 'w') as out_file:
            out_file.write(instruction)
        print(data)
    

    
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='input parser')
    parser.add_argument('--file', metavar='path', required=True,
                        help='the path to the exported json file')
    args = parser.parse_args()
    print(args.file)
    main(file_path=args.file)