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

Neil Aronson picture Neil Aronson · Jul 12, 2016 · Viewed 7.4k times · Source

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.

Answer

Ben Squire picture Ben Squire · Oct 4, 2016

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?