Is it possible to write a query in Cypher to format the output of the following query into a JSON object?
MATCH (n:Artist{name:'Metallica'})-[r]->(m:Album)
RETURN {node: n, neighbours: { type(r): collect(m) }}
Of course, this is not a valid Cypher query. I'm trying to see if there's any way to write a query that generates the concept proposed here? One another problem (other than type(r):) is with m and it needs to be grouped by type(r).
As Gabor Szarnyas said, in the current implementation of the cypher it is impossible to do exactly as you wish. But you can do it using user defined procedure apoc.map.fromPairs from APOC library:
MATCH (n:Artist {name:'Metallica'})-[r]->(m:Album)
WITH n, type(r) AS relType, collect(m) AS albums
WITH n, collect([relType, albums]) as pairs
CALL apoc.map.fromPairs( pairs ) YIELD value as neighbours
RETURN { node: n, neighbours: neighbours }
You can construct a map using map literals. According to its documentation:
From Cypher, you can also construct maps. Through REST you will get JSON objects; in Java they will be java.util.Map<String,Object>.
However, you have to specify the keys in the map in advance - you cannot use variables/expressions (such the value of type(r)) as keys. The closest I could get to your requirements is the following:
MATCH (n:Artist {name:'Metallica'})-[r]->(m:Album)
WITH n, type(r) AS albumType, collect(m) AS albums
RETURN { node: n, works: collect({ type: albumType, albums: albums }) }
(The query is syntactically correct, but I did not test it on any data.)
See also this related question: Cypher query with literal map syntax & dynamic keys
Related
I have multiple nodes and relationships in neo4j, certain nodes have relationship depth as 4, while certain have 2. I'm using neo4j's HTTP API to get the data in graph format
Sample query:
MATCH p= (n:datasource{resource_key:'ABCD'})-[:is_dataset_of]-(c:dataset)-[q]-(v:dataset_columns)-[s]-(b:component)-[w]-(e:dashboard) return p
If i use this query then i can get output if this exact relationship is present but I also want to get the output if the 2nd relationship is not available, Any pointers on how to achieve this?
Here is one way:
MATCH p = (:person1 {hobby: 'gamer'})-[:knows]-(:person2)
RETURN p
UNION ALL
MATCH p = (:person1 {hobby: 'gamer'})-[:knows]-(:person2)--(:person3)
RETURN p
The UNION clause combines the results of 2 queries. And the ALL option tells UNION to not bother to remove duplicate results (since the 2 subqueries will never produce the same paths).
If you really want the path to be returned, you can do something along these lines, using apoc (https://neo4j-contrib.github.io/neo4j-apoc-procedures/3.4/nodes-relationships/path-functions/)
MATCH requiredPath=(n)-[r]->(m)
OPTIONAL MATCH optionalPath = (m)-[q]->(s)
RETURN apoc.path.combine(requiredPath,optionalPath) AS p
graph snippet
I have a Shape with a list of Points.
I have the following requirements:
1) retrieve an ordered set of Points;
2) insert/remove a Point and preserve the order of the rest of the Points
I can achieve this by:
A) Point has a sequence integer property that could be used to order;
B) Add a :NEXT relationship between each Point to create a linked list.
I'm new to Neo4j so not sure which approach is preferable to satisfy the requirements?
For the first requirement, I wrote the following queries and found the performance for the traversal to be poor but Im sure its a badly constructed query:
//A) 146 ms
Match (s:Shape {id: "1-700-y11-1.1.I"})-[:POINTS]->(p:Point)
return p
order by p.sequence;
//B) Timeout! Bad query I know, but dont know the right way to go about it!
Match path=(s:Shape {id: "1-700-y11-1.1.I"})-[:POINTS]->(p1:Point)-[:NEXT*]->(p2:Point)
return collect(p1, p2);
To get ordered list of points use a slightly modified version of the second query:
Match path=(s:Shape {id: "1-700-y11-1.1.I"})-[:POINTS]->(P1:Point)
-[:NEXT*]-> (P2:Point)
WHERE NOT (:Point)-[:NEXT]->(P1) AND
NOT (P2)-[:NEXT]->(:Point)
RETURN TAIL( NODES( path) )
And for example query to delete:
WITH "id" as pointToDelete
MATCH (P:Point {id: pointToDelete})
OPTIONAL MATCH (Prev:Point)-[:NEXT]->(P)
OPTIONAL MATCH (P)-[:NEXT]->(Next:Point)
FOREACH (x in CASE WHEN Prev IS NOT NULL THEN [1] ELSE [] END |
MERGE (Prev)-[:NEXT]->(Next)
)
DETACH DELETE P
I loaded Neo4j with Pizza.owl file using hermit reasoner and Java.
when i pass a simple query:
match (n) where n="name:Pizza" return n;
am getting the following error
Don't know how to compare that. Left: Node[1]{name:"owl:Thing"} (NodeProxy); Right: "name:Pizza" (String)
Is NodeProxy a datatype? How can I make both of them to be compared. Can I do casting while querying? Any query to change datatype of the entire graph nodes? How to check the type of the node?
You are comparing a node n to a string "name:Pizza", which doesn't make sense. What you want is to compare the property name of node n with the string "Pizza": WHERE n.name = "Pizza". The whole query then looks like this
MATCH (n)
WHERE n.name = "Pizza"
RETURN n
Nodes don't really have types. Take a look at the Neo4j manual to more about nodes, relationships, properties and labels and about Cypher in general, and the WHERE clause in particular.
I have a Cypher query which I'd like to expand to be summed up over a list of matching nodes.
My query looks like this:
MATCH (u:User {name: {input} })-[r:USES]-(t) RETURN SUM(t.weight)
This matches one User node, and I'd like to adjust it to match a list of User nodes and then perform the aggregation.
My current implementation just calls the query in a loop and performs the aggregation outside of Cypher. This results in slightly inaccurate results and a lot of API calls.
Is there a way to evaluate the Cypher query against a list of elements (strings in my case)?
I'm using Neo4j 2.1 or 2.2.
Cheers
You can use the IN operator and pass in an array of usernames:
MATCH (u:User)-[r:USES]-(t)
WHERE u.name in ['John','Jim','Jack']
RETURN u.name, SUM(t.weight)
Instead of the array here you can use an parameter holding and array value as well:
MATCH (u:User)-[r:USES]-(t)
WHERE u.name in {userNames}
RETURN u.name, SUM(t.weight)
userNames = ['John','Jim','Jack']
I have a very simple data model with source-[:link]->target. I'd like to find out all the nodes, which have no incoming links e.g. the "roots" of my data model. How do I do that in Cypher?
You can filter on null values
START target=node(*)
MATCH target<-[r?:link]-source
WHERE r is null
RETURN target
For details, refer Cypher where clause documentation
Alternatively, you can also do
START target=node(*)
WHERE not(target<-[:link]-source)
RETURN target
*Note: not tested
start n=node(*)
match n<-[?]-m
with n, count(m) as c
where c=0
return n