Recently I switched from using Cypher queries to neomodel
OGM. Although it simplified codebase, there's still an issue I can't solve. While using Cypher, I could simply write CREATE <object> IF NOT EXISTS
, and execution plan would be understandable enough: if exists - do nothing, if doesn't - create. After switching to neomodel
, I've created following:
- Service responsible for calling Neo4J using Neomodel:
from models.neo4j_models import (
...
)
from neomodel import config, db
...
class GraphDBService:
def __init__(self, uri: str, username: str, password: str):
...
self._initialize_db() # IMPORTANT: called every time when service is created
...
def _initialize_db(self) -> None:
"""Initialize database with constraints and indexes"""
try:
db.install_all_labels()
logger.info("Neo4j constraints and indexes installed via neomodel")
except Exception as e:
logger.error(f"Error initializing Neo4j schema: {str(e)}", exc_info=True)
raise GraphDBError(f"Failed to initialize Neo4j schema: {str(e)}")
- Model to be created (
models.neo4j_models
):
from neomodel import (
StringProperty, ...
)
class Company(StructuredNode):
"""
Company node representing an anization where a person has worked
"""
name = StringProperty(unique_index=True, required=True)
...
It works as expected (according to their doc), but what I do not like is following:
- Use service 1st time
- All models, relationships and so on are created (as expected)
- Disconnect from service and reconnect again
- All models and so on are created again (as expected)
During second round, my trace is heavily cluttered by logs of following type:
cv-storage-service-1 | Found models.neo4j_models.Company
cv-storage-service-1 | + Creating node unique constraint for name on label Company for class models.neo4j_models.Company
cv-storage-service-1 | {code: Neo.ClientError.Schema.EquivalentSchemaRuleAlreadyExists} {message: An equivalent constraint already exists, 'Constraint( id=17, name='constraint_unique_Company_name', type='NODE PROPERTY UNIQUENESS', schema=(:Company {name}), ownedIndex=16 )'.}
Although I could find a solution checking whether calling _initialize_db()
is justified or not, I would prefer simpler solution: just to pass a construct/flag/whatever that will tell neo sort of IF <this> NOT EXISTS, create
. How could I do that?
If passing extra param is not an option, how could I change logs dropping straight from Neo4J? Core issue here is that all these "Errors" contain word Error
, thus awfully increasing number of errors in log, and instead of having 100x+ Sorry, can't create, it already exists
INFO-messages I get 100x+ "errors" that need not to be solved (from my point of view).
Workaround in this GitHub issue works as of now, but to be honest, I'd prefer to get a solution rather than a workaround :)
Tech: MacOS Sonoma 14.6.1, Python 3.11, neomodel 5.4.4