Tom Carrick
Tom Carrick

Reputation: 6616

Neo4j check if node exists before creating?

I have a feeling I'm going about this all wrong. But anyway.

I have an sql database which has essentially a purposefully denormalised table which I've constructed to make this task easier for me, so I can just grab stuff from one table.

What I have is a table of pairs, something like this:

user_lo | user_hi | something_else | other stuff
1000    | 1234    | 1231251654     | 123
1050    | 1100    | 1564654        | 45648
1080    | 1234    | 456444894648   | 1

And so on.

So for my neo4j graph db, I want each user id as a node, the other stuff isn't too important but will be the stuff in the relations basically.

I only want one node for each user, so my feeling is that if I do something like this:

while (rs.next()) {
    node_lo = db.createNode();
    node_lo.setProperty("user_id", rs.getInt(1));
    node_hi = db.createNode();
    node_hi.setProperty("user_id", rs.getInt(2));
}

That when we add the node with user_id 1234 for the second time, it will just create a new node, but I what I want is for it to just grab this node instead of creating it so I can add it to the relationship to 1080 in this case.

So what is the way to do this?

Upvotes: 8

Views: 19835

Answers (6)

Wesam Nabki
Wesam Nabki

Reputation: 2614

use this function: where: ID is the key which you want to check if already exist Type: is the type of the node ( the label) this function will create the node and return it, then you can add more properties.

public static Node getOrCreateUserWithUniqueFactory( long ID, GraphDatabaseService graphDb, String Type )
{
    UniqueFactory<Node> factory = new UniqueFactory.UniqueNodeFactory( graphDb, Type )
    {
        @Override
        protected void initialize( Node created, Map<String, Object> properties )
        {

            created.addLabel( DynamicLabel.label( Type ) );
            created.setProperty( "ID", properties.get( "ID" ) );
        }
    };

    return factory.getOrCreate( "ID", ID );
}

Upvotes: 1

Burhan
Burhan

Reputation: 83

using cypher query, you can create a unique node with the following syntax,

CYPHER 2.0 merge (x:node_auto_index{id:1})

when making a REST call, one can make batch insertion like

$lsNodes[] = array(

            'method'=> 'POST', 'to'=> '/cypher',

            'body' => array(
                'query' => 'CYPHER 2.0 merge (x:node_auto_index{id_item:{id}})',
                'params'    =>  array('id'=>1)
            ),
            'id'=>0

        );

        $sData = json_encode($lsNodes);

similarly for creating relationships in a batch request, do the following

$lsNodes[] = array(

                        'method'=> 'POST', 'to'=> '/cypher',

                        'body'  => array(
                            'query'     => 'start a=node:node_auto_index(id={id1}), b = node:node_auto_index(id={id2}) create unique a-[:have{property:30}}]-b;',
                            'params'    => array(
                                'id1'  => 1, 'id2'=>  2
                            )
                        ),
                        'id'    => 0

                    );
$sData = json_encode($lsNodes);

Upvotes: 0

Shannon Monasco
Shannon Monasco

Reputation: 15

Normalize your SQL tables to look like nodes and relationships. Then with cypher in your migration you can make the migration rerunnable by something like

start a = node:node_auto_index('id:"<PK_Value>"')
delete a

create a = {id: "<PK_VALUE>", etc}

for nodes and since you should have in your many-to-many middle table:

start LHS = node:node_auto_index('id:"<LHS_PK>"'),
      RHS = node:node_auto_index('id:"<RHS_PK>"')
create unique LHS=[:<relType> {<rel props>}]->RHS

now you will end up with no duplicates and can rerun as much as you like.

Upvotes: 1

Andres
Andres

Reputation: 1454

Have you looked at CREATE UNIQUE?

If you can't use Cypher, maybe you can use unique nodes?

Upvotes: 4

Michael Hunger
Michael Hunger

Reputation: 41676

You'll probably want to use the UniqueNodeFactory provided by Neo4j.

    public Node getOrCreateUserWithUniqueFactory( String username, GraphDatabaseService graphDb )
{
    UniqueFactory<Node> factory = new UniqueFactory.UniqueNodeFactory( graphDb, "UserNodes" )
    {
        @Override
        protected void initialize( Node created, Map<String, Object> properties )
        {
            created.setProperty( "id", properties.get( "id" ) );
        }
    };

    return factory.getOrCreate( "id", id );
}

Upvotes: 2

Nicholas
Nicholas

Reputation: 7501

Use an index to search, and if no result of found, create a new one.

Index<Node> userIndex = graphDatabaseService.index().forNodes('UserNodes');

IndexHits<Node> userNodes = userIndex.get('id', 1234);

if(!userNodes.hasNext()){
    //Create new User node
} else {
    Node userNode = userNodes.next();
}

Is this the type of operation you are looking for?

Upvotes: 4

Related Questions