Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature request: return a path in a query/mutation with @cypher #194

Open
maiieul opened this issue Sep 25, 2019 · 2 comments
Open

feature request: return a path in a query/mutation with @cypher #194

maiieul opened this issue Sep 25, 2019 · 2 comments

Comments

@maiieul
Copy link

maiieul commented Sep 25, 2019

Expected feature example:

type Query {
  getUserRankedCategories(userName: String!): Path
   @cypher(
      statement: "MATCH path=( (user:User{name: userName})-[rated:RATED]->(category:Category) ) RETURN path"
    )
}

with something like:

type Path {
  user: User
  category: Category
  rated: Rating
}
type User {
  name: String
}

type Category {
   name: String
}

type Rating @relation (name: "RATED") {
  from: User
  to: Category
  value: Int!
}

but I get this error when I put a relationship type in another type like this:

type Path {
  user: User
  category: Category
  rated: Rating
}
throw new Error("The '".concat(field.name.value, "' field on the '").concat(typeName, "' type uses the '").concat(relatedAstNode.name.value, "'\n    but '").concat(relatedAstNode.name.value, "' comes from '").concat(fromName, "' and goes to '").concat(toName, "'"));

ReferenceError: field is not defined
at validateRelationTypeDirectedFields (/home/maieul/Desktop/dev/nexus-backend/api/node_modules/neo4j-graphql-js/dist/augment.js:863:36)
at handleRelationTypeDirective (/home/maieul/Desktop/dev/nexus-backend/api/node_modules/neo4j-graphql-js/dist/augment.js:961:75)
at handleRelationFields (/home/maieul/Desktop/dev/nexus-backend/api/node_modules/neo4j-graphql-js/dist/augment.js:915:23)
at /home/maieul/Desktop/dev/nexus-backend/api/node_modules/neo4j-graphql-js/dist/augment.js:177:17
at Array.forEach ()
at augmentTypeMap (/home/maieul/Desktop/dev/nexus-backend/api/node_modules/neo4j-graphql-js/dist/augment.js:165:37)
at makeAugmentedExecutableSchema (/home/maieul/Desktop/dev/nexus-backend/api/node_modules/neo4j-graphql-js/dist/augment.js:77:26)
at makeAugmentedSchema (/home/maieul/Desktop/dev/nexus-backend/api/node_modules/neo4j-graphql-js/dist/index.js:229:53)
at Object. (/home/maieul/Desktop/dev/nexus-backend/api/src/index.js:10:16)
at Module._compile (internal/modules/cjs/loader.js:778:30)

I haven't found any way to return paths yet using the @cypher directive and even custom resolvers since we must specify a returned object in the typedefs.

I'm not very experienced with neo4j in general, but I feel that the power of neo4j and of graph databases in general, comes from the ability to create (merge, update, delete) and query a certain pattern/path, made of nodes and relationships consistently.

It seems like right now, I can get nodes on their own, relationships on their own, but not them linked together. So it takes many queries or different tricks to get the paths that I want which I fear might be hard to keep consistent when trying to use filter or Ordering and seems a lot less performant than being able to return a path directly.

I might be doing it wrong, but I haven't found any solution in the docs. Any solution right now is more than welcome. But if there are none, could it be added to the list of future features? I think it would be very useful and a greater developer experience.

P.S. I'll post what I've been able to achieve below, even if it doesn't work properly (or even at all) if it can help towards achieving this feature.

@maiieul maiieul changed the title how to return a path in a query with @cypher: returning an array of relationships does not work as expected feature request: being able to return an array of paths in a query with @cypher Sep 26, 2019
@maiieul
Copy link
Author

maiieul commented Sep 26, 2019

I have only found workarounds to achieve returning a path since I can't return it directly within the typedefs.

I wanted to be able to return a simple path like (node)-[:relationship]->(node) multiple times but only achieve to return one path and not many.

For this, I used a relationship like this one :

type Rating @relation (name: "RATED") {
  from: User
  to: Category
  value: Int!
}

And I returned it in my query:

type Query {
  getUserRankedCategories(userName: String!): Rating
   @cypher(
      statement: "MATCH (user:User{userName: userName})-[rated:RATED]->(category:Category)) RETURN rated"
    )
}

With this, I'm able to return the path with "(user)" and "(category)" nodes and the "[rated]" relationship.

But when I try to return an array of Ratings like that:

type Query {
  getUserRankedCategories(userName: String!): [Rating]
   @cypher(
      statement: "MATCH (user:User{userName: userName})-[rated:RATED]->(category:Category) RETURN rated, category"
    )
}

I get the following output:
output-path-query

On neo4j browser, if I run such a query, I can get the path directly if I RETURN path or I can get the rated nodes along with the category relationships if I RETURN rated, category.

But it seems that apoc isn't taking into account the second return somehow, perhaps because apoc.cypher.runFirstColumn takes it as if it was written :
"MATCH (user:User{userName: userName})-[rated:RATED]->(category:Category) RETURN rated"

So I'd like to be able to return the corresponding categories and not always only one like in the screenshot.

@maiieul maiieul changed the title feature request: being able to return an array of paths in a query with @cypher feature request: being able to return an array of paths in a query/mutation with @cypher Sep 26, 2019
@maiieul maiieul changed the title feature request: being able to return an array of paths in a query/mutation with @cypher feature request: return a path in a query/mutation with @cypher Sep 26, 2019
@jexp
Copy link
Contributor

jexp commented Sep 28, 2019

I tried to figure out a solution for that a while ago but it's not to pretty.

type Attribute {
  key: String!
  value: String
}

type PGNode {
  id: ID!
  labels: [String]
  properties: [Attribute]
}

type PGRelationship {
  id: ID!
  type: String!
  start: PGNode
  end: PGNode
  properties: [Attribute]
}
type PGPathSegment {
  start:PGNode
  end: PGNode
  relationship: PGRelationship
}
type PGPath {
  start: PGNode
  end: PGNode
  length: Int
  segments: [PGPathSegemnt]

}


match path=()-->()
with [n IN nodes(path) | n {id:id(n), labels:labels(n), properties: [k in keys(n) | {key:k, value:toString(n[k])] as nodes, 
     [r IN rels(path)  | r {id:id(n), type:type(r),     properties: [k in keys(r) | {key:k, value:toString(r[k])] as rels
return { start:nodes[0], end:nodes[-1], length: size(nodes), segments: [idx in range(0,size(nodes)-2) | {start:nodes[idx],end:nodes[idx+1],relationship:rels[idx]} ]}


no guarantees but it should give you an idea

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants