Can you help me to build cypher query? i have following graph db structure:
(parent:Category)-[:subcategory]->(child:Category)
With this graph data i have hierarchical tree with deep level.
I found following code on Stackoverfllow.com and changed for my data:
MATCH (root:Category)-[:subcategory]->(parent:Category)-[:subcategory]->(child:Category)
WITH root, {category: parent, children: collect(child)} AS parent_with_children
WHERE NOT(()-[:subcategory]->(root))
RETURN {category: root, children: collect(parent_with_children)}
But he is build response only for depth with 3 levels of tree. I need bigger. I'm try to build json response like this example:
[
category: {
name: "PC"
children: {
category: {
name: "Parts"
children: {
category: {
name: "CPU"
...
}
}
},
category: {
name: "Accessories"
...
}
}
},
category: {
name: "Laptop"
...
}
]
The Cypher can make recursive calls? I think this will be better.
Thanks.
P.S. I know there are similar questions on SO, but they did not help me.
Cypher is not well suited for dumping out graph data in a tree structure when leaves are at arbitrary depths.
However, with neo4j 3.x, you can get close to what you want if you are able to install the APOC plugin on your server and use the apoc.convert.toTree procedure.
First, let's create some sample data:
CREATE
(c1:Category {name: 'PC'}),
(c1)-[:subcategory]->(c2:Category {name: 'Parts'}),
(c2)-[:subcategory]->(c3:Category {name: 'CPU'}),
(c3)-[:subcategory]->(c4:Category {name: 'CacheRAM'}),
(c1)-[:subcategory]->(c5:Category {name: 'Accessories'}),
(c5)-[:subcategory]->(c6:Category {name: 'Mouse'}),
(c5)-[:subcategory]->(c7:Category {name: 'Keyboard'}),
(c10:Category {name: 'Laptop'}),
(c10)-[:subcategory]->(c20:Category {name: 'Parts'}),
(c20)-[:subcategory]->(c30:Category {name: 'CPU'}),
(c10)-[:subcategory]->(c40:Category {name: 'Accessories'}),
(c40)-[:subcategory]->(c50:Category {name: 'Stylus'});
Then with this query:
MATCH p=(n:Category)-[:subcategory*]->(m)
WHERE NOT ()-[:subcategory]->(n)
WITH COLLECT(p) AS ps
CALL apoc.convert.toTree(ps) yield value
RETURN value;
... you will get N result rows, where N is the number of root Category nodes. Here is a snippet of sample results:
{
...
"row": [
{
"_id": 150,
"_type": "Category",
"name": "PC",
"subcategory": [
{
"_id": 154,
"_type": "Category",
"name": "Accessories",
"subcategory": [
{
"_id": 156,
"_type": "Category",
"name": "Keyboard"
},
{
"_id": 155,
"_type": "Category",
"name": "Mouse"
}
]
},
{
"_id": 151,
"_type": "Category",
"name": "Parts",
"subcategory": [
{
"_id": 152,
"_type": "Category",
"name": "CPU",
"subcategory": [
{
"_id": 153,
"_type": "Category",
"name": "CacheRAM"
}
]
}
]
}
]
}
],
...
"row": [
{
"_id": 157,
"_type": "Category",
"name": "Laptop",
"subcategory": [
{
"_id": 158,
"_type": "Category",
"name": "Parts",
"subcategory": [
{
"_id": 159,
"_type": "Category",
"name": "CPU"
}
]
},
{
"_id": 160,
"_type": "Category",
"name": "Accessories",
"subcategory": [
{
"_id": 161,
"_type": "Category",
"name": "Stylus"
}
]
}
]
}
],
...
}
Related
First of all, I'm new to NEO4J and to CYPHER. So I'm twerking here and there to figure out to get the result I want.
Below is my graph. Let's say it's a simple family tree.
I have come up with this simple cypher query to fetch the direct descendants of the node
MATCH (p:Person {username: "SETHLORDM"})<-[r:CHILD_OF]-(p2)
RETURN {current: p, children: collect(p2)}
and the text version of the result is as below
The above is okay, but I want to get the text result as follows if it's doable with NEO4J.
[
{
"username": "SETHLORDM",
"location": "NO_LOCATION",
"children": [
{
"username": "TESTNODE_1",
"location": "LEFT",
"children": [
{
"username": "TESTNODE_3",
"location": "LEFT",
"children": []
},
{
"username": "TESTNODE_4",
"location": "RIGHT",
"children": []
}
],
},
{
"username": "TESTNODE_2",
"location": "RIGHT",
"children": [
{
"username": "TESTNODE_5",
"location": "RIGHT",
"children": []],
},
{
"username": "TESTNODE_6",
"location": "RIGHT",
"children": []],
}
],
}
],
}
]
Any help regarding this would be highly appreciated. Thank you
One way to approach it is using apoc.convert.toTree (using the plugin apoc).
This can create the tree structure that you are looking for. But, since your tree is bottom-up, the result will be same, meaning each node will point its parent. If you want to get the results as you want, using this method, you will have to change your relations.
For example, using this data:
MERGE (a:Person{key: 1, username: "SETHLORDM"})
MERGE (b:Person{key: 2})
MERGE (c:Person{key: 3})
MERGE (d:Person{key: 4})
MERGE (e:Person{key: 5})
MERGE (f:Person{key: 6})
MERGE (g:Person{key: 7})
MERGE (b)-[:CHILD_OF]-(a)
MERGE (c)-[:CHILD_OF]-(a)
MERGE (d)-[:CHILD_OF]-(b)
MERGE (e)-[:CHILD_OF]-(b)
MERGE (f)-[:CHILD_OF]-(c)
MERGE (g)-[:CHILD_OF]-(c)
and this query:
MATCH path = (p:Person {username: "SETHLORDM"})<-[r:CHILD_OF*..2]-(p2)
WITH collect(path) AS paths
CALL apoc.convert.toTree(paths)
YIELD value
RETURN value;
will give this result:
"_type": "Person",
"child_of": [
{
"_type": "Person",
"child_of": [
{
"_type": "Person",
"_id": 243,
"key": 5
},
{
"_type": "Person",
"_id": 242,
"key": 4
}
],
"_id": 240,
"key": 2
},
{
"_type": "Person",
"child_of": [
{
"_type": "Person",
"_id": 245,
"key": 7
},
{
"_type": "Person",
"_id": 244,
"key": 6
}
],
"_id": 241,
"key": 3
}
],
"_id": 239,
"key": 1,
"username": "SETHLORDM"
}
But changing the links to this:
MERGE (a)-[:CHILDREN]-(b)
MERGE (a)-[:CHILDREN]-(c)
MERGE (b)-[:CHILDREN]-(d)
MERGE (b)-[:CHILDREN]-(e)
MERGE (c)-[:CHILDREN]-(f)
MERGE (c)-[:CHILDREN]-(g)
And adjusting the query to:
MATCH path = (p:Person {username: "SETHLORDM"})-[r:CHILDREN*..2]->(p2)
WITH collect(path) AS paths
CALL apoc.convert.toTree(paths)
YIELD value
RETURN value;
Will provide:
{
"_type": "Person",
"_id": 246,
"children": [
{
"_type": "Person",
"_id": 247,
"children": [
{
"_type": "Person",
"_id": 249,
"key": 4
},
{
"_type": "Person",
"_id": 250,
"key": 5
}
],
"key": 2
},
{
"_type": "Person",
"_id": 248,
"children": [
{
"_type": "Person",
"_id": 252,
"key": 7
},
{
"_type": "Person",
"_id": 251,
"key": 6
}
],
"key": 3
}
],
"key": 1,
"username": "SETHLORDM"
}
Which is now similar to what you wanted...
Bonus: if you are using apoc, you can replace the MATCH query by apoc.path.expandConfig which should be more efficient to larger graphs.
I have a neo4j DB in which user data and relations between them would be stored, the end user will interact with this data from a mobile app (app is in Flutter, we use a nestjs neo4j connector in between). Now we have to enable offline access to data. So the idea was to export the data of the user from neo4j as json and use it when offline, when the device gets online we will make the changes to the DB. I have some problem getting the data as json
This is a rough sample what I am trying to do
The cypher commands to create these nodes
CREATE (c:Computer {name: 'Andy',uid:'123'})
CREATE (d1:Drive {name: 'Drive1',capacity:"2gb",uid:'223'})
CREATE (d2:Drive {name: 'Drive2',capacity:"4gb",uid:'233'})
CREATE (f1:Folder {name: 'desktop',type:"special",uid:'323'})
CREATE (f2:Folder {name: 'mydocuments',type:"special",uid:'333'})
CREATE (f3:Folder {name: 'myprojects',type:"normal",uid:'343'})
CREATE (t1:File {name: 'text1',type:"txt",size:"1kb",uid:'423'})
CREATE (t2:File {name: 'text2',type:"txt",size:"1.5kb",uid:'433'})
CREATE (t3:File {name: 'text3',type:"txt",size:"2kb",uid:'443'})
CREATE (do1:File {name: 'doc1',type:"doc",size:"1mb",uid:'523'})
CREATE (do2:File {name: 'doc2',type:"doc",size:"1.5mb",uid:'533'})
CREATE (do3:File {name: 'doc3',type:"doc",size:"2mb",uid:'543'})
CREATE (c)-[r1:PARTITION{during: 'osinstall'}]->(d1)
CREATE (c)-[r2:PARTITION{during: 'setup'}]->(d2)
CREATE (d1)-[r3:AutoCreated{during: 'osinstall',type:"folder"}]->(f1)
CREATE (d1)-[r4:AutoCreated{during: 'osinstall',type:"folder"}]->(f2)
CREATE (f1)-[r5:Shortcut{type:"folder"}]->(c)
CREATE (f2)-[r6:Shortcut{type:"folder"}]->(c)
CREATE (d2)-[r7:UserCreated{type:"folder"}]->(f3)
CREATE (d2)-[r8:UserCreated{type:"file"}]->(t1)
CREATE (d2)-[r9:UserCreated{type:"file"}]->(t2)
CREATE (f3)-[r10:UserCreated{type:"file"}]->(t3)
CREATE (f3)-[r11:UserCreated{type:"file"}]->(do1)
CREATE (d2)-[r12:UserCreated{type:"file"}]->(do2)
CREATE (do2)-[r13:Shortcut{type:"file"}]->(f1)
CREATE (f3)-[r14:Shortcut{type:"folder"}]->(f1)
CREATE (f1)-[r15:UserCreated{type:"file"}]->(do3)
CREATE (do3)-[r16:Shortcut{type:"file"}]->(f3)
CREATE (c1:Computer {name: 'Randy',uid:'c1-123'})
CREATE (c1d1:Drive {name: 'Drive1',capacity:"1gb",uid:'c1-223'})
CREATE (c1t1:File {name: 'text1',type:"txt",size:"1kb",uid:'c1-423'})
CREATE (c1t2:File {name: 'text2',type:"txt",size:"1.5kb",uid:'c1-433'})
CREATE (c1sh1:SharedDrive {name:"SharedDrive",uid:'c1-s1'})
CREATE (c1)-[c1r1:PARTITION{during: 'osinstall'}]->(c1d1)
CREATE (c1d1)-[c1r2:UserCreated{type:"file"}]->(c1t1)
CREATE (c1d1)-[c1r3:UserCreated{type:"file"}]->(c1t2)
CREATE (c1t1)-[c1r4:Share{type:"file"}]->(c1sh1)
CREATE (c1)-[c1r5:SHAREDPARTITION{during: 'osinstall'}]->(c1sh1)
CREATE (c1)-[common:Network]->(c)
I want to query a root node(say Andy) with the users uid and get the data in the format
{
"name": "Andy",
"uid":"123",
"PARTITION":[
{
"name": "Drive1",
"capacity":"2gb",
"uid":"223",
"Folder":[
{ "name": "desktop","type":"special","uid":"323",
"File":[
"... Detail about file doc3 here.."
],
"Shortcut":[
"... Detail about file doc2 here.."
]
},
{"name": "mydocuments","type":"special","uid":"333"}
]
},
{
"name": "Drive2",
"capacity":"4gb",
"uid":"233",
"Folder":[
{ "name": "myprojects","type":"normal","uid":"343",
"File":[
"...Detail about Files doc1, text3 here..."
],
"Shortcut":[
"... Detail about file doc3 here.."
]
}
],
"File":[
"...Detail about Files text1,text2,doc 2 here..."
]
}
],
"Shortcut":[
{
"name": "desktop","type":"special","uid":"323"
},{
"name": "mydocuments","type":"special","uid":"333"
}
],
"Network":[
{
"name": "Randy",
"uid":"c1-123",
"SHAREDPARTITION":["...HERE ONLY NEED THE files and folders from shareddrive other drives should not show up..."]
}
]
}
I want to add the relations from and to the node as key and for the value add a list of nodes(with their related properties) connected to it and move to the next one. I don't know how to do so. So far I have tried
match (n:Computer{uid:"123"})-[r:PARTITION]->(x)
match b=(x)-[*]->(y)
with collect(b) as c
call apoc.convert.toTree(c) yield value
return value
but this does not return the shortcut file paths properly ie., if I add a shortcut from doc3(at desktop) to myproject, I don't find the file detail with myproject shortcuts I need it at both places at desktop(under files) and myproject(under shortcut) folder. Also the shared computer details are not fetched(all drives must not be fetched just the sharedpartition). Apart from this the return data is not in the expected format and I have to process it in the app after fetching it.
Can someone help me with this?
I am also open to different solutions for neo4j flutter offline.
You can create a connection from the root node then collect them all together. Just make sure you are using the relationship that you want to extract. Below is not exactly you described but closest to your json format.
match b=(n:Computer{uid:"123"})-[r:PARTITION]->(x:Drive)-[]-(y:Folder)-[]-(z:File)
match c=(n)-[:Shortcut]-()
match d=(n)-[:Network]-()-[:SHAREDPARTITION]-()
with collect(b) + collect(c) + collect(d) as t
call apoc.convert.toTree(t) yield value
return value
Result:
{
"name": "Andy",
"uid": "123",
"_type": "Computer",
"_id": 298,
"partition": [
{
"uid": "233",
"_type": "Drive",
"name": "Drive2",
"_id": 300,
"partition.during": "setup",
"capacity": "4gb",
"usercreated": [
{
"uid": "343",
"shortcut": [
{
"uid": "543",
"size": "2mb",
"shortcut.type": "file",
"_type": "File",
"name": "doc3",
"_id": 309,
"type": "doc"
}
],
"_type": "Folder",
"name": "myprojects",
"usercreated": [
{
"uid": "443",
"size": "2kb",
"_type": "File",
"name": "text3",
"_id": 306,
"type": "txt",
"usercreated.type": "file"
},
{
"uid": "523",
"size": "1mb",
"_type": "File",
"name": "doc1",
"_id": 307,
"type": "doc",
"usercreated.type": "file"
}
],
"_id": 303,
"type": "normal",
"usercreated.type": "folder"
}
]
},
{
"uid": "223",
"_type": "Drive",
"name": "Drive1",
"_id": 299,
"partition.during": "osinstall",
"capacity": "2gb",
"autocreated": [
{
"autocreated.during": "osinstall",
"autocreated.type": "folder",
"uid": "323",
"shortcut": [
{
"uid": "533",
"size": "1.5mb",
"shortcut.type": "file",
"_type": "File",
"name": "doc2",
"_id": 308,
"type": "doc"
}
],
"_type": "Folder",
"name": "desktop",
"usercreated": [
{
"uid": "543",
"size": "2mb",
"_type": "File",
"name": "doc3",
"_id": 309,
"type": "doc",
"usercreated.type": "file"
}
],
"_id": 301,
"type": "special"
}
]
}
],
"shortcut": [
{
"uid": "333",
"shortcut.type": "folder",
"_type": "Folder",
"name": "mydocuments",
"_id": 302,
"type": "special"
},
{
"uid": "323",
"shortcut.type": "folder",
"_type": "Folder",
"name": "desktop",
"_id": 301,
"type": "special"
}
],
"network": [
{
"_type": "Computer",
"name": "Randy",
"uid": "c1-123",
"_id": 310,
"sharedpartition": [
{
"_type": "SharedDrive",
"name": "SharedDrive",
"uid": "c1-s1",
"_id": 473,
"sharedpartition.during": "osinstall"
}
]
}
]
}
I am following this example https://www.compose.com/articles/how-to-script-painless-ly-in-elasticsearch/
where BOTH the ORIGINAL fields plus the calculated field (some_scores) are presented in the result document.
{
"_index": "sat",
"_type": "scores",
"_id": "AV3CYR8JFgEfgdUCQSON",
"_score": 1,
"_source": {
"cds": 1611760130062,
"rtype": "S",
"sname": "American High",
"dname": "Fremont Unified",
"cname": "Alameda",
"enroll12": 444,
"NumTstTakr": 298,
"AvgScrRead": 576,
"AvgScrMath": 610,
"AvgScrWrit": 576,
"NumGE1500": 229,
"PctGE1500": 76.85,
"year": 1516
},
"fields": {
"some_scores": [
1152
]
}
}
Now i am doing a _search with the following post body
{
"query": {
"match_all": {}
},
"script_fields": {
"some_scores": {
"script": {
"lang": "painless",
"inline": "\"hello\""
}
}
}
}
but the results i am getting DOESN'T contain the original fields; it only contains the testing field which i hardcoded to hello. Is there anything wrong with my query ?
"hits": [
{
"_index": "abcIndex",
"_type": "data",
"_id": "id_00000025",
"_score": 1.0,
"fields": {
"some_scores": [
"hello"
]
}
}]
You need to explicitly pass _source": ["*"] when using script field.
I was not able to find reason for this , looks like some kind of optimization.
{
"_source": ["*"],
"query": {
"match_all": {}
},
"script_fields": {
"some_scores": {
"script": {
"lang": "painless",
"inline": "doc['authorization']+\"hello\""
}
}
}
I have implemented the function score attribute in my document model which contains a click field that keeps tracks of a number of view per document. Now I want the search results to get more priority and appear at the top based on the clicks per search
My document.rb code
require 'elasticsearch/model'
def self.search(query)
__elasticsearch__.search(
{
query: {
function_score: {
query: {
multi_match: {
query: query,
fields: ['name', 'service'],
fuzziness: "AUTO"
}
},
field_value_factor: {
field: 'clicks',
modifier: 'log1p',
factor: 2
}
}
}
}
)
end
settings index: { "number_of_shards": 1,
analysis: {
analyzer: {
edge_ngram_analyzer: { type: "custom", tokenizer: "standard", filter:
["lowercase", "edge_ngram_filter", "stop", "kstem" ] },
}
},
filter: { ascii_folding: { type: 'asciifolding', preserve_original: true
},
edge_ngram_filter: { type: "edgeNGram", min_gram: "3", max_gram:
"20" }
}
} do
mapping do
indexes :name, type: "string", analyzer: "edge_ngram_analyzer",
term_vector: "with_positions"
indexes :service, type: "string", analyzer: "edge_ngram_analyzer",
term_vector: "with_positions"
end
end
end
Search View is here
<h1>Document Search</h1>
<%= form_for search_path, method: :get do |f| %>
<p>
<%= f.label "Search for" %>
<%= text_field_tag :query, params[:query] %>
<%= submit_tag "Go", name: nil %>
</p>
<% end %>
<% if #documents %>
<ul class="search_results">
<% #documents.each do |document| %>
<li>
<h3>
<%= link_to document.name, controller: "documents", action: "show",
id: document._id %>
</h3>
</li>
<% end %>
</ul>
<% else %>
<p>Your search did not match any documents.</p>
<% end %>
<br/>
When I search for Estamp, I get the results follow in the following order:
Franking and Estamp # clicks 5
Notary and Estamp #clicks 8
So clearly when the Notary and Estamp had more clicks it does not come to the top of the search.How can I achieve this?
This is what I get when I run it on the console.
POST _search
"hits": {
"total": 2,
"max_score": 1.322861,
"hits": [
{
"_index": "documents",
"_type": "document",
"_id": "13",
"_score": 1.322861,
"_source": {
"id": 13,
"name": "Franking and Estamp",
"service": "Estamp",
"user_id": 1,
"clicks": 7
},
{
"_index": "documents",
"_type": "document",
"_id": "14",
"_score": 0.29015404,
"_source": {
"id": 14,
"name": "Notary and Estamp",
"service": "Notary",
"user_id": 1,
"clicks": 12
}
}
]
Here the score of the documents is not getting updated based on the clicks
Without seeing your indexed data it's not easy to answer. But looking at the query one thing comes to my mind, I'll show it with short example:
Example 1:
I've indexed following documents:
{"name":"Franking and Estampy", "service" :"text", "clicks": 5}
{"name":"Notary and Estamp", "service" :"text", "clicks": 8}
Running the same query you provided gave this result:
"hits": {
"total": 2,
"max_score": 4.333119,
"hits": [
{
"_index": "script",
"_type": "test",
"_id": "AV2iwkems7jEvHyvnccV",
"_score": 4.333119,
"_source": {
"name": "Notary and Estamp",
"service": "text",
"clicks": 8
}
},
{
"_index": "script",
"_type": "test",
"_id": "AV2iwo6ds7jEvHyvnccW",
"_score": 3.6673431,
"_source": {
"name": "Franking and Estampy",
"service": "text",
"clicks": 5
}
}
]
}
So everything is fine - document with 8 clicks got higher scoring (_score field value) and the order is correct.
Example 2:
I noticed in your query that name field is boosted with high factor. So what would happen if I had following data indexed?
{"name":"Franking and Estampy", "service" :"text", "clicks": 5}
{"name":"text", "service" :"Notary and Estamp", "clicks": 8}
And result:
"hits": {
"total": 2,
"max_score": 13.647502,
"hits": [
{
"_index": "script",
"_type": "test",
"_id": "AV2iwo6ds7jEvHyvnccW",
"_score": 13.647502,
"_source": {
"name": "Franking and Estampy",
"service": "text",
"clicks": 5
}
},
{
"_index": "script",
"_type": "test",
"_id": "AV2iwkems7jEvHyvnccV",
"_score": 1.5597181,
"_source": {
"name": "text",
"service": "Notary and Estamp",
"clicks": 8
}
}
]
}
Although Franking and Estampy has only 5 clicks, it has much much higher scoring than the second document with greater number of clicks.
So the point is that in your query, the number of clicks is not the only factor that has an impact on scoring and final order of documents. Without the real data it's only a guess from my side. You can run the query yourself with some REST client and check scoring/field/matching phrases.
Update
Based on your search result - you can see that document with id=13 has Estamp term in both fields (name and service). That is the reason why this document got higer scoring (it means that in the algorithm of calculating scoring it is more important to have the term in both fields than have higher number of clicks). If you want clicks field to have bigger impact on the scoring, try to experiment with factor (probably should be higher) and modifier ("modifier": "square" could work in your case). You can check possible values here.
Try for example this combination:
{
"query": {
"function_score": {
... // same as before
},
"field_value_factor": {
"field": "clicks" ,
"modifier": "square",
"factor": 3
}
}
}
}
Update 2 - scoring based only on number of clicks
If the only parameter that should have an impact on scoring should be the value in clicks field, you can try to use "boost_mode": "replace" - in this case only function score is used, the query score is ignored. So the frequency of Estamp term in name and service fields will have no impact on the scoring. Try this query:
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "Estamp",
"fields": [ "name", "service"],
"fuzziness": "AUTO"
}
},
"field_value_factor": {
"field": "clicks",
"factor": 1
},
"boost_mode": "replace"
}
}
}
It gave me:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 5,
"hits": [
{
"_index": "script",
"_type": "test",
"_id": "AV2nI0HkJPYn0YKQxRvd",
"_score": 5,
"_source": {
"name": "Notary and Estamp",
"service": "Notary",
"clicks": 5
}
},
{
"_index": "script",
"_type": "test",
"_id": "AV2nIwKvJPYn0YKQxRvc",
"_score": 4,
"_source": {
"name": "Franking and Estamp",
"service": "Estamp",
"clicks": 4
}
}
]
}
}
This may be the one you are looking for (note the values "_score": 5 and "_score": 4 are matching the number of clicks).
I am trying to get the relationship type of a very simple Cypher query, like the following
MATCH (n)-[r]-(m) RETURN n, r, m;
Unfortunately this return an empty object for r. This is troublesome since I can't distinguish between the different types of relationships. I can monkey patch this by adding a property like [r:KNOWS {type:'KNOWS'}] but I am wondering if there isn't a direct way to get the relationship type.
I even followed the official Neo4J tutorial (as described below), demonstrating the problem.
Graph Setup:
create (_0 {`age`:55, `happy`:"Yes!", `name`:"A"})
create (_1 {`name`:"B"})
create _0-[:`KNOWS`]->_1
create _0-[:`BLOCKS`]->_1
Query:
MATCH p=(a { name: "A" })-[r]->(b)
RETURN *
JSON RESPONSE BODY:
{
"results": [
{
"columns": [
"a",
"b",
"p",
"r"
],
"data": [
{
"row": [
{
"name": "A",
"age": 55,
"happy": "Yes!"
},
{
"name": "B"
},
[
{
"name": "A",
"age": 55,
"happy": "Yes!"
},
{},
{
"name": "B"
}
],
{}
]
},
{
"row": [
{
"name": "A",
"age": 55,
"happy": "Yes!"
},
{
"name": "B"
},
[
{
"name": "A",
"age": 55,
"happy": "Yes!"
},
{},
{
"name": "B"
}
],
{}
]
}
]
}
],
"errors": []
}
As you can see, I get an empty object for r, which makes it impossible to distinguish between the relationships.
NOTE: I am running Neo4J v.2.2.2
Use the type() function.
MATCH (n)-[r]-(m) RETURN type(r);
Added distinct.
MATCH (n)-[r]-(m) RETURN distinct type(r);