neo4j-graphql / neo4j-graphql-js

NOTE: This project is no longer actively maintained. Please consider using the official Neo4j GraphQL Library (linked in README).
Other
608 stars 148 forks source link

How do I return the node's ID? #16

Closed gustavlrsn closed 6 years ago

gustavlrsn commented 6 years ago

Thanks for this great tool - it makes connecting graphql with neo4j a joy :).

However, I can't figure out how do I define the schema so that I get the ID of the node back? (I'm very new to neo4j..)

jexp commented 6 years ago

Glad you like it. You can return an "_id" field for each node which then contains the neo4j-id.

Please try and let me know if it works for you. Also if you have any other suggestions for missing capabilities or features feel free to raise them as issues.

What is the use-case you're using the graphql-extension for?

gustavlrsn commented 6 years ago

Thank you for the response! Tried adding an _id field to the schema definition like this (also have nodeId as a work-around):

type Need {
  _id: ID
  nodeId: ID!
  title: String!
  description: String
  guide: Person @relation(name: "GUIDES", direction: "IN")
  realizer: Person @relation(name: "REALIZES", direction: "IN")
  fulfilledBy: [Responsibility] @relation(name: "FULFILLS", direction: "IN")
  dependsOnNeeds: [Need] @relation(name: "DEPENDS_ON", direction: "OUT")
  dependsOnResponsibilites: [Responsibility] @relation(name: "DEPENDS_ON", direction: "OUT")
}

However the _id field returned null.

As for missing capabilities, I would love support for GraphQL interface types, as well as more support in creating mutations!

As for the use-case, I'm helping out to build sort of a decentralized management platform, more info here: https://github.com/theborderland/realities :)

arne-at-daten-und-bass commented 6 years ago

You could do it with a @cypher directive (calling the Neo4j id() function)

# Returned as Integer
type Need {
  _id: Int @cypher(statement: "WITH {this} AS this RETURN ID(this)")
  <...>
}

# Returned as ID/String
type Need {
  _id: ID @cypher(statement: "WITH {this} AS this RETURN ID(this)")
  <...>
}

Maybe there are other/better ways ... but for me it worked on the default Neo4j movie database.

gustavlrsn commented 6 years ago

@arne-at-daten-und-bass thanks for you suggestion! I tried this but getting an error unfortunately:

{
  "data": {
    "needs": null
  },
  "errors": [
    {
      "message": "Unknown function 'apoc.cypher.runFirstColumn' (line 1, column 49 (offset: 48))\n\"MATCH (need:Need {}) RETURN need { .title ,_id: apoc.cypher.runFirstColumn(\"WITH {this} AS this RETURN ID(this)\", {this: need}, false)} AS need SKIP 0\"\n                                                 ^",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "needs"
      ]
    }
  ]
}
johnymontana commented 6 years ago

Adding the default _id field is a feature that has not yet been implemented. I'll add this soon.

@gustavlrsn Did you install the APOC procedure library? APOC is required to make use of the @cypher schema directives.

kibagateaux commented 6 years ago

Thanks for the tips for querying neo4j id. For some reason it only works if ID is not a required field in the schema. _id: ID works fine but _id: ID! throws the error below. I don't understand why this is happening since ids are auto-generated by database and from following the stacktrace it seems to do with the recursive function buildCypherSelection passing a null parameter tailSelections to itself which it then tries to access on the subsequent call.

Dependencies

    "apollo-server-lambda": "^1.3.0",
    "graphql-tools": "^2.13.0",
    "neo4j-driver": "^1.5.1",
    "neo4j-graphql-js": "^0.1.6"

Graphiql error message:

{
  "data": {
    "AllUsers": null
  },
  "errors": [
    {
      "message": "Cannot read property 'selections' of null",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "AllUsers"
      ]
    }
  ]
}

Stacktrace:

TypeError: Cannot read property 'selections' of null
    at buildCypherSelection (/Users/kiba/code/djinnii-serverless/graphql/node_modules/neo4j-graphql-js/dist/index.js:134:246)
    at buildCypherSelection (/Users/kiba/code/djinnii-serverless/graphql/node_modules/neo4j-graphql-js/dist/index.js:137:12)
    at cypherQuery (/Users/kiba/code/djinnii-serverless/graphql/node_modules/neo4j-graphql-js/dist/index.js:82:51)
    at neo4jgraphql (/Users/kiba/code/djinnii-serverless/graphql/node_modules/neo4j-graphql-js/dist/index.js:37:15)
    at AllUsers (/Users/kiba/code/djinnii-serverless/graphql/src/resolvers.js:1:620)
    at resolveFieldValueOrError (/Users/kiba/code/djinnii-serverless/graphql/node_modules/graphql/execution/execute.js:498:12)
    at resolveField (/Users/kiba/code/djinnii-serverless/graphql/node_modules/graphql/execution/execute.js:462:16)
    at /Users/kiba/code/djinnii-serverless/graphql/node_modules/graphql/execution/execute.js:311:18
    at Array.reduce (<anonymous>)
    at executeFields (/Users/kiba/code/djinnii-serverless/graphql/node_modules/graphql/execution/execute.js:308:42)
    at executeOperation (/Users/kiba/code/djinnii-serverless/graphql/node_modules/graphql/execution/execute.js:236:122)
    at executeImpl (/Users/kiba/code/djinnii-serverless/graphql/node_modules/graphql/execution/execute.js:133:26)
    at Object.execute (/Users/kiba/code/djinnii-serverless/graphql/node_modules/graphql/execution/execute.js:110:229)
    at doRunQuery (/Users/kiba/code/djinnii-serverless/graphql/node_modules/apollo-server-core/dist/runQuery.js:98:26)
    at /Users/kiba/code/djinnii-serverless/graphql/node_modules/apollo-server-core/dist/runQuery.js:22:54
    at <anonymous>
    at process._tickDomainCallback (internal/process/next_tick.js:228:7)
arne-at-daten-und-bass commented 6 years ago

I could reproduce that @kibagateaux . The difference is that, if it is a mandatory field, the field is of another type (GraphQLNonNull) and the check (see below) for GraphQLScalarType does not work.

Would you mind checking if this here https://github.com/arne-at-daten-und-bass/neo4j-graphql-js/commit/b4c9140c612651f99940fb951e1228b985d89125 resolves it in your case?

#Before
let fieldIsScalar = fieldType.constructor.name === "GraphQLScalarType"; // FIXME: DRY
#After
let fieldIsScalar = fieldType.ofType ? fieldType.ofType.constructor.name === "GraphQLScalarType" : fieldType.constructor.name === "GraphQLScalarType"; // FIXME: DRY

In my case it did. Then I would make a PR.

johnymontana commented 6 years ago

In addition to the approach of using a @cypher directive, https://github.com/neo4j-graphql/neo4j-graphql-js/commit/9fbc9add1d79d51012267d3b6470f6c142217567 adds a convenience handler that will return the internal id for the field _id, which mirrors the functionality in https://github.com/neo4j-graphql/neo4j-graphql

Note that this field, _id must be added to schema.