pyorient
pyorient copied to clipboard
what is the correct way to write get_or_create_edge
I wrote get_or_create_vertex and it works fine (at least I can see the data correctly)
# this works great
def orientdb_get_or_create_vertex(vertex=None, **kwargs):
link_data = vertex.query(**kwargs).all()
if link_data:
link = link_data[0]
else:
link = vertex.create(
**kwargs
)
return link
But I could not figure out a way to do get_or_create_edge. Usingedge.create(_from, _to)
directly is creating duplications every time I run the script to update the data from mongo to orientdb(selected data only). how do I implement orientdb_relation_create_edge ?
def orientdb_relation_create_edge(g=None, edge=None, _from=None, _to=None):
e = g.inE(_to, [edge]).outE(_from, [edge]).all() # not sure ?
print (e)
if e:
e = e[0]
else:
e = edge.create(_from, _to) # using this directly is creating duplications,
return e
This code quite dirty (you may need some adaptations), but it works well for me (I use it as base class for all Edge classes in OGM):
# Create Edge Class
class RelationshipGetOrCreateInterface(object):
@classmethod
def get_or_create(cls, from_node, to_node, **kwargs):
"""
Get first or create according to criteria
:param from_node:
:param to_node:
:param kwargs:
:return: created or found edge object
"""
get_query_dict = {
"in": to_node,
"out": from_node,
}
get_query_dict.update(kwargs)
# import ipdb; ipdb.set_trace()
# slow:
# results = cls.objects.query(**get_query_dict)
# optimized:
results = cls.filter(from_node, to_node, **kwargs)
count = len(results)
if count>0:
# get first
if count > 1:
LOG.debug("Multiple results for get_or_create filter query "
"return the first object only!!!")
LOG.debug(get_query_dict)
# found something, return first
LOG.debug("Get the EDGE %s from DB! Data: %s" % (cls.__name__, results[0].__dict__))
return results[0]
else:
# create
return cls.create(from_node, to_node, **kwargs)
@classmethod
def filter(cls, from_node, to_node, **kwargs):
rel_class_filter = cls.registry_name
additional_filter_of_relation = ""
if kwargs:
# support only equality filters/ only strings!!!!
for k,v in kwargs.items():
additional_filter_of_relation += " and %s=%s" % (k, json.dumps(unicode(v)))
if hasattr(to_node, "_id"):
to_node_id = to_node._id
elif hasattr(to_node, "id"):
to_node_id = to_node.id
else:
raise Exception("Can not detect id for node: %s" % to_node)
if hasattr(from_node, "_id"):
from_node_id = from_node._id
elif hasattr(from_node, "id"):
from_node_id = from_node.id
else:
raise Exception("Can not detect id for node: %s" % from_node)
command_str = "SELECT expand(outE('%s')[in=%s%s]) FROM %s" % (rel_class_filter,
to_node_id,
additional_filter_of_relation,
from_node_id)
LOG.info(command_str)
try:
orient_records = cls.objects.g.client.query(command_str)
results = cls.objects.g.edges_from_records(orient_records)
return results
except Exception as e:
import socket
LOG.warning(e)
LOG.warning("Error happened during orient command: %s" % command_str)
return []
@classmethod
def filter_by_attributes(cls, **kwargs):
"""
more flexible but slow method of filtering Edges in orientDB, must be used when it is impossible
to filter by to_node and from_node (which makes query much faster)
:param kwargs:
:return: ORM edges
"""
orient_records = cls.objects.query(**kwargs)
return orient_records
@classmethod
def create(cls, from_node, to_node, **kwargs):
edge = graph.create_edge(
cls,
from_node,
to_node,
**kwargs)
LOG.debug("Creating a new Relationshisp in GraphDB: %s" % cls.__name__)
str_from = str(from_node)
str_to = str(to_node)
if kwargs:
LOG.debug(kwargs)
return edge
# fast but hardcody method which makes possible to search relations with filtering
# by string attribute
@classmethod
def get(cls, from_node, to_node, **kwargs):
"""
Gets edge according to filter criteria
Raises Exception if Not Found or Multiple Objects returned
:param kwargs:
:return:
"""
results = cls.filter(from_node, to_node, **kwargs)
return cls.handle_results_for_get(results, from_node, to_node, **kwargs)
def handle_results_for_get(self, results, from_node, to_node, **kwargs):
count = len(results)
if count==1:
# found something
LOG.info("Got the node from DB! %s" % kwargs)
return results[0]
elif count>1:
LOG.exception("Multiple results for get filter query "
"kwargs: %s" % kwargs)
for each_obj in results:
LOG.debug(each_obj)
raise Exception("Multiple Objects in get method!")
else:
# No objects found
raise Exception("No objects according to filtering criteria: %s" % kwargs)
Would be happy to get feedback with improvements for the snippet class above