2015-01-06 10 views
5

ho qualche difficoltà con la py2neo trovare e find_one (http://py2neo.org/2.0/essentials.html)py2neo: Graph.find_one con chiave multipla/valori

Quello che voglio in Cypher è:

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

Say, dove ci sono più di una chiave/set di valori (ad esempio se ci sono più di una 'Alice' nel grafico).

mio problema è che non so cosa regalare graph.find_one, un codice di lavoro è:

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

Quello che vorrei è qualcosa di simile (Questo non funziona!):

Una possibile soluzione (cattiva) sarebbe quella di creare un oggetto graph.find, quindi eseguire il loop delle proprietà dei risultati e cercare l'età, ma questa soluzione non mi piace.

Bonus: Sarebbe possibile con graf.find fare qualcosa come età> 25?


EDIT: "soluzione" Nuovo

find_person = "MATCH (p: Person) DOVE p.name = {N} e p.age = {A} RITORNO 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"}) 

Quello che non mi piace di questo è che manca la nota-oggetto, (e io non comprendere appieno il RecordListList, e come navigare è ben segnalato)

risposta

2

in base alla risposta @elyase e la py2neo.Graph.find originale, ho fatto questo codice. Non esitate a commentare e migliorare .. :-)

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 

uso di find_dict_one:

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

L'utilizzo di find_dict con 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"}) 

L'utilizzo di find_dict senza parametri:

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

Se si guarda allo source code, si scopre che sfortunatamente find e find_one non supportano questo tipo di query. Si consiglia di utilizzare direttamente il 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) 
+1

Grazie per la risposta .. :-) Il problema con t la soluzione di cappello è che è davvero irradiante al passato nei parametri. Ho apportato una modifica al post, con un'idea leggermente migliore, ma ancora non ancora presente. –

+0

@ThomasRepsdorph, ho aggiornato la mia risposta per spiegare come passare i parametri, questo è essenzialmente ciò che dovrebbe essere 'find', si potrebbe inviare una richiesta di pull una volta che funziona. – elyase

+0

Sembra divertente, ci proverò .. MrGreen E grazie per il tuo aiuto. –

Problemi correlati