neomodel icon indicating copy to clipboard operation
neomodel copied to clipboard

Unexpected behaviour with `get_or_create`

Open RafaelAMello opened this issue 5 years ago • 1 comments

Hey there! This isssue seems very similar to this issue: https://github.com/neo4j-contrib/neomodel/issues/462

However I decided to create a new one - let me know if you like me to merge this with above.

This issue illustrates some strange behaviour when using get_or_create in this code:

from neomodel import StructuredNode
from neomodel import  StringProperty, IntegerProperty
from neomodel import RelationshipFrom, RelationshipTo

class Movie(StructuredNode):
    oid                 = StringProperty(unique_index=True)
    title               = StringProperty()
    genres              = RelationshipTo("Genre", "IS_KIND")


class Genre(StructuredNode):
    name        = StringProperty()
    genre_id    = IntegerProperty(unique_index=True)
    movies      = RelationshipFrom('Movie', "IS_KIND")


movies_data = [{'oid': '8844', 'title': 'Jumanji'},{'oid': '862','title': 'Toy Story'}]

genre_data =[
     [{'genre_id': 16, 'name': 'Animation'}, {'genre_id': 35, 'name': 'Comedy'}, {'genre_id': 10751, 'name': 'Family'}],
     [{'genre_id': 12, 'name': 'Adventure'}, {'genre_id': 14, 'name': 'Fantasy'},{'genre_id': 10751, 'name': 'Family'}]
]

movie_objects = Movie.get_or_create(*movies_data)

for n, genre in enumerate(genre_data):
    Genre.get_or_create(*genre, relationship=movie_objects[n].genres)

When I run the above I get this error:

Traceback (most recent call last):
  File "/Users/rafmello/GitHub/oscar-worthy/python/lib/python3.7/site-packages/neomodel/util.py", line 212, in cypher_query
    response = session.run(query, params)
  File "/Users/rafmello/GitHub/oscar-worthy/python/lib/python3.7/site-packages/neo4j/__init__.py", line 492, in run
    self._connection.fetch()
  File "/Users/rafmello/GitHub/oscar-worthy/python/lib/python3.7/site-packages/neobolt/direct.py", line 422, in fetch
    return self._fetch()
  File "/Users/rafmello/GitHub/oscar-worthy/python/lib/python3.7/site-packages/neobolt/direct.py", line 464, in _fetch
    response.on_failure(summary_metadata or {})
  File "/Users/rafmello/GitHub/oscar-worthy/python/lib/python3.7/site-packages/neobolt/direct.py", line 759, in on_failure
    raise CypherError.hydrate(**metadata)
neobolt.exceptions.ConstraintError: Node(53687) already exists with label `Genre` and property `genre_id` = 16

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "help.py", line 30, in <module>
    Genre.get_or_create(*genre, relationship=movie_objects[n].genres)
  File "/Users/rafmello/GitHub/oscar-worthy/python/lib/python3.7/site-packages/neomodel/core.py", line 433, in get_or_create
    results = db.cypher_query(query, params)
  File "/Users/rafmello/GitHub/oscar-worthy/python/lib/python3.7/site-packages/neomodel/util.py", line 33, in wrapper
    return func(self, *args, **kwargs)
  File "/Users/rafmello/GitHub/oscar-worthy/python/lib/python3.7/site-packages/neomodel/util.py", line 223, in cypher_query
    raise UniqueProperty(ce.message)
neomodel.exceptions.UniqueProperty: Node(53687) already exists with label `Genre` and property `genre_id` = 16
Failed to write data to connection Address(host='localhost', port=7687) (Address(host='::1', port=7687, flow_info=0, scope_id=0)); ("0; 'Underlying socket connection gone (_ssl.c:2263)'")
Failed to write data to connection Address(host='localhost', port=7687) (Address(host='::1', port=7687, flow_info=0, scope_id=0)); ("0; 'Underlying socket connection gone (_ssl.c:2263)'")

This behaviour is unexpected because I am looking to utilize the unique_index on the Genre model to get genre's that already exist.

RafaelAMello avatar Nov 24 '19 06:11 RafaelAMello

Running: neomodel==3.3.2

RafaelAMello avatar Nov 24 '19 06:11 RafaelAMello

Any updates on this? I am experiencing the same issue.

kl-thamm avatar Nov 22 '22 14:11 kl-thamm

Update from my side: It does work when you use a UniqueIdProperty, even when you supply a value that is other than the default value.

There are two differences when you use the UniqueIdProperty compared to the string property: 1) It inherits from Property instead of NormalizedProperty 2) It ignores the kwargs and it sets a default value as well as unique_index=True (https://github.com/neo4j-contrib/neomodel/blob/da8b1e4322c64490dd83a0b62eacf77fe2f85b3e/neomodel/properties.py).

As the NormalizedProperty does not define a construct itself, it seems unlikely to me that the problem arises there. So this leaves me with option 2 - maybe it is required to set a default value (or as it is mutually exclusive) the required kwarg.

I tested that now and setting required = True seems to do the job.

kl-thamm avatar Nov 22 '22 17:11 kl-thamm

Seems fixed based on comment, so closing for cleaning up the Issues log. Feel free to re-open

mariusconjeaud avatar Sep 26 '23 15:09 mariusconjeaud