2015-01-06 3 views
5

ich einige Probleme mit der haben py2neo zu finden und find_one (http://py2neo.org/2.0/essentials.html)py2neo: Graph.find_one mit mehreren Schlüssel/Werte

Was ich in Cypher will, ist:

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

Sag mal, wo es mehr als ein Schlüssel/Wert-Satz (z. B. wenn mehr als ein 'Alice' in dem Graphen vorhanden ist).

Mein Problem ist, dass ich weiß nicht, was graph.find_one zu geben, ein Arbeitscode lautet:

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

Was Ich mag würde, ist so etwas wie (Dies funktioniert nicht!):

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

Eine mögliche (schlechte) Lösung wäre, eine graph.find zu machen, und dann durch die Ergebnisse Eigenschaften und suchen Sie nach dem Alter, aber ich mag diese Lösung nicht.

Bonus: Wäre es mit graph.find möglich, etwas wie Alter> 25 zu tun?


EDIT: Neue "Lösung"

find_person = "MATCH (p: Person) WHERE p.name = {N} UND 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"}) 

Was ich mag über das nicht bin ich vermisse das Note-Objekt, (und ich verstehe nicht ganz den RecordListList, und wie es navigieren nicley)

Antwort

2

Basierend auf @elyase Antwort und die ursprüngliche py2neo.Graph.find ich diesen Code gemacht haben. Bitte fühlen Sie sich frei zu äußern und zu verbessern .. :-)

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 

Verwendung von find_dict_one:

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

Verwendung von find_dict mit Tupel:

>>> 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"}) 

Verwendung von find_dict ohne Tupel:

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

Wenn Sie sich die source code ansehen, werden Sie leider feststellen, dass find und find_one diese Art von Abfragen nicht unterstützen. Sie sollten direkt Cypher interface verwenden:

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) 
+1

Danke für deine Antwort .. :-) Das Problem mit t Hut-Lösung ist, dass es wirklich in Parametern nach Vergangenheit ausstrahlt. Ich habe einen Beitrag zum Post gemacht, mit einer etwas besseren Idee, aber immer noch nicht da. –

+0

@ThomasRepsdorph, habe ich meine Antwort aktualisiert, um zu erklären, wie Parameter übergeben werden, das ist im Wesentlichen, was "finden" sollte tun, können Sie eine Pull-Anfrage senden, sobald Sie es funktioniert. – elyase

+0

Klingt lustig, ich werde das versuchen .. :-D Und danke für deine Hilfe. –

Verwandte Themen