2015-04-24 5 views
5

Gibt es eine Möglichkeit, UNWIND für potenziell leere Sammlungen (z. B. OPTIONAL UNWIND g) zu verwenden?Cypher: Verwenden Sie UNWIND mit potenziell leeren Sammlung

Zum Beispiel kommt es in der angefügten Abfrage vor, dass die Sammlung (Elemente) manchmal leer ist (3. Block), aber die Ergebnisse der anderen Sammlungen sind immer noch relevant.

Hier möchte ich einige Zahlen für ein Sub-Diagramm knacken und die Zählungen der verschiedenen Knotentypen (Gruppe, Benutzer, Ort, Artikel, Artikelgruppen) zurückgeben. Die Itemgroups können nur über die Items abgeleitet werden. Und da so viele Elemente an mehrere Benutzer angehängt sind, wäre es sehr langsam, wenn ich die Elementgruppen direkt in den zweiten Block einschließe, ohne zuerst zu aggregieren.

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) 

Ich habe einen Workaround gefunden, aber ich bin nicht wirklich glücklich damit. Wenn ich einen Dummy-Knoten in die Objektauflistung einfüge, kann ich ihn jedes Mal abschalten, ohne die Ergebnisse zu verlieren.

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) 

Ich überlege, zwei separate Abfragen zu schreiben, aber das würde zu komplexer Client-Logik führen.

Alle Ideen und Hinweise werden sehr geschätzt.

Danke!

+1

ich diesen gleichen conundrum hatte. Ich habe auch den "Dummy" -Knoten root übernommen. Es fehlte definitiv an Eleganz, aber es schien gut zu funktionieren. Ich würde mich über andere mögliche Lösungen, insbesondere elegantere, interessieren. –

Antwort

1

Ich empfehle Ihnen, statt so viele zu entspannen, versuchen Sie Ihre Abfrage neu zu organisieren.

Es ist eine schnelle Refactoring ein, aber es ist nur ein Vorschlag;) überprüfen 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) 

Die Untergruppe wird die Standalone-Wurzelgruppen als auch, bc die * 0 .. sammeln. Das erste optionale Match ist also nicht mehr nötig.

Ich habe die Zählungen so früh wie möglich gemacht. Nur Nutzer benötigten auf der zweiten Ebene, um Artikeldaten zu sammeln. Viel Spaß :)

7

Sie verwenden:

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