2015-04-24 19 views
5

C'è un modo per utilizzare UNWIND per raccolte potenzialmente vuote (ad esempio OPTIONAL UNWIND g)?Cypher: utilizzare UNWIND con una raccolta potenzialmente vuota

Ad esempio, nella query allegata si verifica che la raccolta (elementi) sia vuota a volte (3 ° blocco), ma i risultati delle altre raccolte sono ancora pertinenti.

Qui voglio raggruppare alcuni numeri per un sotto-grafico e restituire i conteggi di vari tipi di nodi (gruppo, utenti, posizione, articolo, gruppi di articoli). I gruppi di articoli possono essere ricavati solo tramite gli articoli. E poiché ci sono così tanti elementi collegati a più utenti, sarebbe molto lento se includessi i gruppi di articoli direttamente nel secondo blocco senza prima aggregarli.

MATCH(group: Group {id: "12345"}) 
OPTIONAL MATCH(group) - [: IS_PARENT * 0..] - > (subgroup: Group) 

WITH collect(distinct subgroup) as groups 
UNWIND groups as group 
    OPTIONAL MATCH(u: User) - [: BELONGS_TO] - > (group) 
    OPTIONAL MATCH(u) --(i: Item) 
    OPTIONAL MATCH(u) --(l: Location) 
WITH groups, collect(distinct u) as users, collect(distinct i) as items, collect(distinct l) as locations 
UNWIND items as i 
    OPTIONAL MATCH(i) --(ig: FunctionalArea) 
RETURN length(groups), length(users), length(items), length(locations), count(distinct ig) 

Ho trovato una soluzione, ma non ne sono davvero contento. Quando inserisco un nodo fittizio nella raccolta articoli, posso svolgerlo ogni volta senza perdere i risultati.

MATCH(group: Group {id: "12345"}) 
OPTIONAL MATCH(group) - [: IS_PARENT * 0..] - > (subgroup: Group) 

WITH collect(distinct subgroup) as groups 
UNWIND groups as group 
    OPTIONAL MATCH(u: User) - [: BELONGS_TO] - > (group) 
    OPTIONAL MATCH(u) --(i: Item) 
    OPTIONAL MATCH(u) --(l: Location) 
WITH groups, collect(distinct u) as users, collect(distinct i) as items, collect(distinct l) as locations 

>> 
MATCH(ig:ItemGroup) 
WITH groups, users, ([head(collect(ig))] + items) as items, locations 
<< 
UNWIND items as i 
    OPTIONAL MATCH(i) --(ig: FunctionalArea) 
RETURN length(groups), length(users), length(items), length(locations), count(distinct ig) 

Sto considerando di scrivere due query separate, ma ciò porterebbe a una logica client complessa.

Tutte le idee e suggerimenti sono molto apprezzati.

Grazie!

+1

Ho avuto questo stesso enigma. Sono andato anche alla radice del nodo 'dummy'. Mancava decisamente l'eleganza ma sembrava funzionare bene. Sarei interessato a conoscere altre potenziali soluzioni, specialmente quelle più eleganti. –

risposta

1

ti suggerisco, invece di usare così tante attività, provare a riorganizzare la query.

sua una rapida refactoring uno, ma il suo solo un suggerimento;) verificare che pls:

MATCH(group: Group {id: "12345"})-[:IS_PARENT*0..]->(subgroup: Group) 
OPTIONAL MATCH(u: User)-[: BELONGS_TO]->(subgroup) 
OPTIONAL MATCH(u) -- (l: Location) 

WITH COLLECT(DISTINCT subgroup) AS g, COLLECT(DISTINCT u) AS uc, 
    count(distinct subgroup) as groups, 
    count(distinct u) as users, 
    count(distinct l) as locations 

UNWIND uc as u 

OPTIONAL MATCH(u) --(i: Item) 
OPTIONAL MATCH(i) --(ig: FunctionalArea) 

RETURN groups, users, count(DISTINCT i) AS items, locations, count(distinct ig) 

Il sottogruppo raccoglierà i gruppi radice standalone così, bc il * 0 ... Quindi la prima partita opzionale non è più necessaria.

Ho fatto i conti il ​​più presto possibile. Solo gli utenti necessari al secondo livello per la raccolta di dati sugli articoli. Enjoy :)

7

si potrebbe usare:

UNWIND (CASE items WHEN [] then [null] else items end) as item

Problemi correlati