Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
03-02-2020 06:51 PM
**I have a simple graph of Part nodes and CHILD_OF relationships. There is a property "index" on the "CHILD_OF" relationship that determines the order of the children.
This cypher works like a charm
MATCH p = (:Part { name:"Root" })<-[i:CHILD_OF *0..]-(c:Part)
RETURN REDUCE (path = '1', index IN i | path + '.' + index.index) AS path, c.name as name
ORDER BY path
It returns the following, which is exactly what I am trying to achieve with Graphql. Note that "Sub Assy 1" appears in two places in the tree.
│"path" │"name" │
│"1" │"Root" │
│"1.1" │"Sub Assy 1"│
│"1.1.1" │"Part 1" │
│"1.1.2" │"Part 2" │
│"1.2" │"Sub Assy 2"│
│"1.2.1" │"Sub Assy 1"│
│"1.2.1.1"│"Part 1" │
│"1.2.1.2"│"Part 2" │
│"1.3" │"Sub Assy 3"│
Here is the Graphql schema I came up with:
type Part {
name: String
children: [Children]
}
type Children @relation(name: "CHILD_OF") {
from: Part
to: Part
_id: ID
index: String
}
type Tree {
path: String
name: String
}
type Query {
tree(root: String):[Tree]
@cypher(statement:
"""MATCH p = (:Part {name: $root}) <-[:Children *0..]-(c:Part) with *, relationships(p) as i
RETURN REDUCE (path = '1', child IN i | path + '.' + child.index) AS path, c.name as name
ORDER BY path""")
}
This is my Graphql Playground query:
query{tree(root: "Root"){
path
name
}}
This is returned:
{
"errors": [
{
"message": "String(\"1\") (of class org.neo4j.values.storable.StringWrappingStringValue)",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"tree"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"code": "Neo.DatabaseError.General.UnknownError",
"name": "Neo4jError",
"stacktrace": [
"Neo4jError: String(\"1\") (of class org.neo4j.values.storable.StringWrappingStringValue)",
"",
" at captureStacktrace (/home/rchevalier/dev/grand-stack/api/node_modules/neo4j-driver/lib/v1/result.js:199:15)",
" at new Result (/home/rchevalier/dev/grand-stack/api/node_modules/neo4j-driver/lib/v1/result.js:65:19)",
" at _newRunResult (/home/rchevalier/dev/grand-stack/api/node_modules/neo4j-driver/lib/v1/transaction.js:354:10)",
" at Object.run (/home/rchevalier/dev/grand-stack/api/node_modules/neo4j-driver/lib/v1/transaction.js:238:14)",
" at Transaction.run (/home/rchevalier/dev/grand-stack/api/node_modules/neo4j-driver/lib/v1/transaction.js:104:26)",
" at /home/rchevalier/dev/grand-stack/api/node_modules/neo4j-graphql-js/dist/index.js:102:25",
" at TransactionExecutor._safeExecuteTransactionWork (/home/rchevalier/dev/grand-stack/api/node_modules/neo4j-driver/lib/v1/internal/transaction-executor.js:134:22)",
" at TransactionExecutor._executeTransactionInsidePromise (/home/rchevalier/dev/grand-stack/api/node_modules/neo4j-driver/lib/v1/internal/transaction-executor.js:122:32)",
" at /home/rchevalier/dev/grand-stack/api/node_modules/neo4j-driver/lib/v1/internal/transaction-executor.js:61:15",
" at new Promise (<anonymous>)"
]
}
}
}
],
"data": {
"tree": null
}
}
I tried this query and was able to get all the properties returned without error, but it is not the result that I want.
query{Part{
_id
name
children{
from{
index
_id
}
}
}}
{
"data": {
"Part": [
{
"_id": "10135",
"name": "Root",
"children": {
"from": [
{
"index": "1",
"_id": "10136"
},
{
"index": "2",
"_id": "10137"
},
{
"index": "3",
"_id": "10138"
}
]
}
},
{
"_id": "10136",
"name": "Sub Assy 1",
"children": {
"from": [
{
"index": "1",
"_id": "10139"
},
{
"index": "2",
"_id": "10140"
}
]
}
},
{
"_id": "10137",
"name": "Sub Assy 2",
"children": {
"from": [
{
"index": "1",
"_id": "10136"
}
]
}
},
{
"_id": "10138",
"name": "Sub Assy 3",
"children": {
"from": []
}
},
{
"_id": "10139",
"name": "Part 1",
"children": {
"from": []
}
},
{
"_id": "10140",
"name": "Part 2",
"children": {
"from": []
}
}
]
}
}
So something is obviously wrong with my Schema and/or tree query. Any suggestions are appreciated.
Solved! Go to Solution.
03-03-2020 05:40 PM
Yea, that was the issue. Here is the query:
type Query {
tree(root: String):[Tree]
@cypher(statement:
"""MATCH p = (:Part {name: $root}) <-[:CHILD_OF *0..]-(c:Part) with *, relationships(p) as i
with REDUCE (path = '1', index IN i | path + '.' + index.index) AS path, c.name as name
ORDER BY path
RETURN { path: path, name: name }"""
)
}
And the result in GraphQL Playground:
{
"data": {
"tree": [
{
"path": "1",
"name": "Root"
},
{
"path": "1.1",
"name": "Sub Assy 1"
},
{
"path": "1.1.1",
"name": "Part 1"
},
{
"path": "1.1.2",
"name": "Part 2"
},
{
"path": "1.2",
"name": "Sub Assy 2"
},
{
"path": "1.2.1",
"name": "Sub Assy 1"
},
{
"path": "1.2.1.1",
"name": "Part 1"
},
{
"path": "1.2.1.2",
"name": "Part 2"
},
{
"path": "1.3",
"name": "Sub Assy 3"
}
]
}
}
03-02-2020 11:24 PM
I believe you still need to specify the relationship in your Part definition like:
children: [Children] @relation(name: "CHILD_OF", direction: "IN")
in order for the schema to explicitly know what you're after. It may also be better to rename the nodes as Parent and Child to make it even more clear.
03-03-2020 02:47 AM
Thanks for the reply Michael. Unfortunately that did not change the result.
As far as renaming the nodes, any node can both a child and a parent so it wouldn't be meaningful to do that. For example, "Sub Assy 1" is a child of "Root" and a parent of "Part 1" and "Part 2".
03-03-2020 04:05 PM
DOH! I think I just figured out what has been staring me in the face for two weeks. My query output is actually not JSON it's just a bunch of strings like so:
│"path" │"name" │
│"1" │"Root" │
│"1.1" │"Sub Assy 1"│
It needs to look like this:
{
"data": {
"tree": [
{
"path: "1",
"name": "Root",
},
{
"path: "1.1",
"name": "Sub Assy 1",
},
...
]
}
Any ideas on how to do that?
If I'm not mistaken, this has just become a neo4j question
03-03-2020 03:19 AM
No worries. I know you need to specify the direction of the relationship as I've shown you above but I'm just not sure your query type can accept the tree structure. You might return it as a map, and get a JSON object back.
03-03-2020 05:40 PM
Yea, that was the issue. Here is the query:
type Query {
tree(root: String):[Tree]
@cypher(statement:
"""MATCH p = (:Part {name: $root}) <-[:CHILD_OF *0..]-(c:Part) with *, relationships(p) as i
with REDUCE (path = '1', index IN i | path + '.' + index.index) AS path, c.name as name
ORDER BY path
RETURN { path: path, name: name }"""
)
}
And the result in GraphQL Playground:
{
"data": {
"tree": [
{
"path": "1",
"name": "Root"
},
{
"path": "1.1",
"name": "Sub Assy 1"
},
{
"path": "1.1.1",
"name": "Part 1"
},
{
"path": "1.1.2",
"name": "Part 2"
},
{
"path": "1.2",
"name": "Sub Assy 2"
},
{
"path": "1.2.1",
"name": "Sub Assy 1"
},
{
"path": "1.2.1.1",
"name": "Part 1"
},
{
"path": "1.2.1.2",
"name": "Part 2"
},
{
"path": "1.3",
"name": "Sub Assy 3"
}
]
}
}
04-03-2020 04:23 PM
Thanks all, this saved me a tonne of time.
All the sessions of the conference are now available online