Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

py2neo - updating existing node with new properties w/uniqueness constraint (merge_one)

I've been trying to figure out a way to adapt the merge_one functionality from py2neo v2 to v3. I read in a Google group that "The merge_one method no longer exists in v3 as you should be able to use merge in all cases instead." but I can't figure out how to easily use regular merge in v3.

I'm trying to recreate Nicole White's neo4j twitter example project with a small modification. She used merge_one. There are uniqueness constraints on (u:User) - u.username and (t:Tweet) - t.id. Her script always has the same properties for Tweet and User nodes, but I am making a case where sometimes I want to go back and add more properties to an existing node with merge. However I get the error

py2neo.database.status.ConstraintError: Node 178 already exists with label Tweet and property "id"=[***]

I understand this is because when I have for example a Tweet that already exists with just an id and then I try to do

        tw_dict = {'id'=t['id'], 'text':t['text'], 'created':t['created_at'],
               'rts':t['retweet_count'],
               'favs':t['favorite_count'], 'lang':t['lang']}
        tweet = Node("Tweet", **tw_dict)
        graph.create(tweet)

merge is not finding the same tweet with all those properties and when it tries to create one is running into the uniqueness constraint on Tweet's id. It looks like the merge_one function would have solved this, but it's not available in v3. So instead I've implemented the following:

    exists = graph.find_one("Tweet", "id", t['id'])
    if exists:
        exists['text'] = t['text']
        exists['created'] = t['created_at']
        exists['rts'] = t['retweet_count']
        exists['favs'] = t['favorite_count']
        exists['lang'] = t['lang']
    else:
        tw_dict = {'text':t['text'], 'created':t['created_at'],
               'rts':t['retweet_count'],
               'favs':t['favorite_count'], 'lang':t['lang']}
        tweet = Node("Tweet", **tw_dict)
        graph.create(tweet)

but this seems repetitive to me. Is there not an easier way in py2neo to do something like updating an existing node with new properties and still specifying a property with a unique constraint (in this case id)? I think in Cypher I would do a merge on just the id and then set on match or set on create but I don't see how to do that with py2neo. I also tried to find in the documentation something that would allow an update of properties from a dictionary with an existing node but can't.

like image 878
Neil Aronson Avatar asked Jul 12 '16 16:07

Neil Aronson


2 Answers

Two things;

1.) tweet.push() has been deprecated. The docs suggest using graph.push(tweet).

2.) I am having trouble to get this working with a transaction such as:

transaction = graph.begin()
transaction.merge(tweet)
transaction.graph.push(tweet)
transaction.commit()

Any suggestion on the difference between using graph.merge and transaction.merge?

like image 168
Ben Squire Avatar answered Nov 17 '22 08:11

Ben Squire


py2neo v3 now has graph.merge(), which you can use to the same effect.

First find or create the node with graph.merge(), matching only on its unique property, then update its other non-unique properties with node.push(). You would've had to do the same thing with graph.merge_one(), just with a slightly different syntax.

from py2neo import Graph, Node
graph = Graph()

tweet = Node('Tweet', id=123)
graph.merge(tweet)
tweet['text'] = 'Hello World'
tweet.push()

I should update that twitter script to use py2neo v3; thanks for the reminder.

like image 32
Nicole White Avatar answered Nov 17 '22 08:11

Nicole White