Py2neo: Graph.find_one with multiple keys / values

I have some problems with py2neo find and find_one ( http://py2neo.org/2.0/essentials.html )

In Cypher I want:

MATCH (p:Person) WHERE p.name='Alice' AND p.age=22 RETURN p 

Say where there is more than one set of keys / values ​​(for example, if the column has more than one "Alice").

My problem is that I do not know what to give graph.find_one, working code:

 graph.find_one('Person', 'name', 'Alice') 

What I would like is something like (this doesn't work!):

 graph.find_one('Person', {'name': 'Alice', 'age': 22}) 

A possible (bad) solution would be to make graph.find, and then scroll through the properties of the results and look for age, but I don't like this solution.

Bonus: Is it possible to do something like age> 25 using the .find chart?


EDIT: New "Solution"

find_person = "MATCH (p: Person) WHERE p.name = {N} AND p.age = {A} RETURN p"

 >>> tx = graph.cypher.begin() >>> tx.append(find_person, {'N': 'Alice', 'A': 22}) >>> res = tx.process() >>> print(res[0][0][0]) (n423:Person {age:22,name:"Lisa"}) 

What I don’t like about this, I skip the Note object, (and I do not fully understand the RecordListList and how to navigate in it nicley)

+5
source share
2 answers

Based on @elyase's answer and source py2neo.Graph.find, I made this code. Please feel free to comment and improve .. :-)

 def find_dict(graph, label, key_value=None, limit=None): """ Iterate through a set of labelled nodes, optionally filtering by property key/value dictionary """ if not label: raise ValueError("Empty label") from py2neo.cypher.lang import cypher_escape if key_value is None: statement = "MATCH (n:%s) RETURN n,labels(n)" % cypher_escape(label) else: # quote string values d = {k: "'{}'".format(v) if isinstance(v, str) else v for k, v in key_value.items()} cond = "" for prop, value in d.items(): if not isinstance(value, tuple): value = ('=', value) if cond == "": cond += "n.{prop}{value[0]}{value[1]}".format( prop=prop, value=value, ) else: cond += " AND n.{prop}{value[0]}{value[1]}".format( prop=prop, value=value, ) statement = "MATCH (n:%s ) WHERE %s RETURN n,labels(n)" % ( cypher_escape(label), cond) if limit: statement += " LIMIT %s" % limit response = graph.cypher.post(statement) for record in response.content["data"]: dehydrated = record[0] dehydrated.setdefault("metadata", {})["labels"] = record[1] yield graph.hydrate(dehydrated) response.close() def find_dict_one(graph, label, key_value=None): """ Find a single node by label and optional property. This method is intended to be used with a unique constraint and does not fail if more than one matching node is found. """ for node in find_dict(graph, label, key_value, limit=1): return node 

using find_dict_one:

 >>> a = find_dict_one(graph, 'Person', {'name': 'Lisa', 'age': 23}) >>> print(a) (n1:Person {age:23,name:"Lisa"}) 

Using find_dict with a tuple:

 >>> a = find_dict(graph, 'Person', {'age': ('>', 21)}, 2) >>> for i in a: >>> print(i) (n2:Person {age:22,name:"Bart"}) (n1:Person {age:23,name:"Lisa"}) 

Using find_dict without a tuple:

 >>> a = find_dict(graph, 'Person', {'age': 22}, 2) >>> for i in a: >>> print(i) (n2:Person {age:22,name:"Bart"}) 
+2
source

If you look at the source code , you will find that, unfortunately, find and find_one do not support this type of query. You must directly use the Cypher interface :

 d = {'name': 'Alice', 'age' : 22} # quote string values d = {k:"'{}'".format(v) if isinstance(v, basestring) else v for k,v in d.items()} cond = ' AND '.join("p.{}={}".format(prop, value) for prop, value in d.items()) query = "MATCH (p:Person) {condition} RETURN p" query = query.format(condition=cond) # "MATCH (p:Person) p.age=22 AND p.name='Alice' RETURN p" results = graph.cypher.execute(query) 
+5
source

Source: https://habr.com/ru/post/1210460/


All Articles