How to concenate multiple lists in neo4j - neo4j

I was wondering wether the following would be possible with Neo4j.
Suppose I have a class of nodes, say (event:Event) whereas every Event has a tags property ([String]).
Now I can return all those arrays just fine like:
MATCH (event:Event) RETURN event.tags
However I don't understand yet how I could combine the output for the different node results to be collected in one list. Is such a thing possible with Cypher? Of course one could always programatically solve this thing, but as far as I understand Cypher offers reduce as well as native list addition.

If you can use APOC library use flatten function for collections:
MATCH (event:Event)
RETURN apoc.coll.flatten(COLLECT(event.tags))
COLLECT(event.tags) will combine all results into single list (list of lists of tags)
apoc.coll.flatten(..) will flatten the list of lists into single list
If for some reason you can't use APOC, use reduce:
MATCH (event:Event)
RETURN REDUCE(s = [], tags IN COLLECT(event.tags) | s + tags)

Map Projection may do most of what you're asking.
map projection documentation
You can start with a node and add to it.
MATCH (user:User)-[:TRIGGERED]->(event:Event) WITH event {.*, user_id:user.user_id} as user_event
This would give you an array of events with the added parameter of user_id.

Related

Neo4J Matching Nodes Based on Multiple Relationships

I had another thread about this where someone suggested to do
MATCH (p:Person {person_id: '123'})
WHERE ANY(x IN $names WHERE
EXISTS((p)-[:BELONGS]-(:Face)-[:CORRESPONDS]-(:Image)-[:HAS_ACCESS_TO]-(:Dias {group_name: x})))
MATCH path=(p)-[:ASSOCIATED_WITH]-(:Person)
RETURN path
This does what I need it to, returns nodes that fit the criteria without returning the relationships, but now I need to include another param that is a list.
....(:Dias {group_name: x, second_name: y}))
I'm unsure of the syntax.. here's what I tried
WHERE ANY(x IN $names and y IN $names_2 WHERE..
this gives me a syntax error :/
Since the ANY() function can only iterate over a single list, it would be difficult to continue to use that for iteration over 2 lists (but still possible, if you create a single list with all possible x/y combinations) AND also be efficient (since each combination would be tested separately).
However, the new existenial subquery synatx introduced in neo4j 4.0 will be very helpful for this use case (I assume the 2 lists are passed as the parameters names1 and names2):
MATCH (p:Person {person_id: '123'})
WHERE EXISTS {
MATCH (p)-[:BELONGS]-(:Face)-[:CORRESPONDS]-(:Image)-[:HAS_ACCESS_TO]-(d:Dias)
WHERE d.group_name IN $names1 AND d.second_name IN $names2
}
MATCH path=(p)-[:ASSOCIATED_WITH]-(:Person)
RETURN path
By the way, here are some more tips:
If it is possible to specify the direction of each relationship in your query, that would help to speed up the query.
If it is possible to remove any node labels from a (sub)query and still get the same results, that would also be faster. There is an exception, though: if the (sub)query has no variables that are already bound to a value, then you would normally want to specify the node label for the one node that would be used to kick off that (sub)query (you can do a PROFILE to see which node that would be).

Neo4J stacked query for desicion tree and expert system

I am new to Neo4J and struggling to get the output I need without extra external processing. I am pretty sure that Neo4J is easily capable of doing that. Please advice on best approach.
I have a 2 types of nodes: Ingredient and Function that are connected using relation that has property of {Weight: 1}. I am querying a list of ingredients and I want to get a sum of connections multiplied by weight of each connection leading to each distinct function.
Here's what I came up with.
MATCH (q:Ingredient)-[r]->(p) WHERE q.RefNo IN [1,2,3] RETURN r,p
This produces following output
{"weight":1}│{"Function":"X1"}
{"weight":0.5}│{"Function":"X1"}
{"weight":0.7}│{"Function":"X2"}
{"weight":0.4}│{"Function":"X3"}
{"weight":0.5}│{"Function":"X4"}
What I want to get in a single/stacked query is
X1:1.5, X2:1=0.7, X3:0.4, X4:0.5
Please advice on possible solution of this problem.
Almost there, you just need to use an aggregation function (in this case, sum()) on the weight, and the Function property as your non-aggregation column:
MATCH (q:Ingredient)-[r]->(p)
WHERE q.RefNo IN [1,2,3]
RETURN p.Function, sum(r.weight) as weight
Or if you only want a single row result:
MATCH (q:Ingredient)-[r]->(p)
WHERE q.RefNo IN [1,2,3]
WITH p, sum(r.weight) as weight
RETURN collect(p {.Function, weight}) as functionWeights

Getting endNodes from a list of matched nodes

Starting with Neo4j, I am pretty sure, this question could be even stupid because the solution might be so easy. But I am not sure how to solve this, I want to combine two queries:
First I search for nodes, which are all themselves parent nodes:
MATCH (parentnodes:DemoMenue) WHERE (parentnodes)-[:IS_PARENT_OF]-> () RETURN parentnodes
Then I want do get the endNodes for each of the matched parentnodes above. If just doing it with one specified parentnode it would for example work like this:
MATCH (x:DemoMenue {title: "A2"})-[r]-() RETURN endNode(r)
Now what is the suggested way/technique in Cypher to apply my second query to each of the matching parentnodes of my first query?
Your two queries can be merged into one without using a foreach loop:
MATCH (parentnodes:DemoMenue)-[r:IS_PARENT_OF]-> () RETURN endNode(r)
If you want to do something for each result in a collection, you can use Foreach, but keep in mind that you can only use SET in foreach, not return.
And to complete my answer, your query is not 'returning' any collection, so you can't use foreach on it, you'll have to use collect before
Why don't you just use:
MATCH (parentnodes:DemoMenue)-[:IS_PARENT_OF]-> (endNode)
RETURN endNodes

Neo4j Cypher - Excluding relationships by type in cypher query?

Single relationships can be excluded by types using
Match (n:Person)-[r]-(m:Person) where type(r)<>"FRIENDS" return n,r,m
Is there a way to exclude multilevel relationships with cypher?
Match (n:Person)-[r*2..4]-(h:Hobby) where type(r)<>"FRIENDS" return n,r,h
Sure, you can do that. Like this:
Match (n:Person)-[r*2..4]-(h:Hobby)
where NONE( rel in r WHERE type(rel)="FRIENDS")
return n,r,h
Your query doesn't work because with multi-level paths, your r is a collection of relationships rather than a single one. So you can use any of the predicates on collections to do the filtering that you want.
Here, I chose NONE with type(rel)=FRIENDS, which means that you'll only get the result back if NONE of the relationships are of type FRIENDS. But you might instead want to use ANY or ALL, depending on what your query is supposed to mean.
Anyway, the main point here is to use a predicate function to turn a collection of things into a single boolean value.
You can use the ALL or ANY predicates for this:
MATCH p=(n:Person)-[*2..4]-(h:Hobby)
WHERE ALL(x in relationships(p) WHERE type(x) <> "FRIENDS")
RETURN n,r,h
Use the ALL predicate to make sure every relationship along that path is not a FRIEND. Use ANY to make sure you have at least one relationship not being FRIEND.

Neo4J Arrays in MATCH query

The intention of my Query is to mark similar words.
CREATE CONSTRAINT ON (n:Word) ASSERT n.title IS UNIQUE
MATCH (n) WHERE ID(n)={id}
MERGE (o:Word{title:{title}})
WITH n,o MERGE n-[r:SIMILAR{location:'{location}'}]->o
RETURN ID(o)
n is a existing Word. I want to create the relationsship & the other Word (o) if they don't exist yet.
The Problem with this query is, that it works for one title, but if I use a Array with titles the title of the Word o is the whole Array.
Can you suggest me another Query that does the same and/or a way to pass multiple values to title.
I'm using the Neography Gem on Rails e.g. the REST API
To use individual values in a parameter array you can use FOREACH, something like
MATCH (n)
WHERE ID (n) = {id}
FOREACH (t IN {title} |
MERGE (o:Word {title:t})
MERGE n-[:SIMILAR]->o
)
If you want to pass location also as a parameter (it is actually a string literal in your current query), such that merge operations for n should happen for each title, location pair in a parameter array, you can try
FOREACH (map IN {maps} |
MERGE (o:Word {title:map.title})
MERGE n-[:SIMILAR {location:map.location}]->o
)
with a parameter that looks something like
{
"maps": [
{
"title":"neography",
"location":"1.."
},{
"title":"coreography",
"location":"3.."
}
]
}
Other suggestions:
It's usually not great to look up nodes by internal id from parameter. In some cases when chaining queries it may be fine, but in most cases label index lookup would be better: MATCH (n:Word {title:"geography"})
If you are not using the transactional cypher endpoint, give it a shot. You can then make one or more calls with one or more queries in each call within one transaction. Performance improves and you may find you don't need to send the more complex parameter object, but can send many simple queries.

Resources