When a remote relationship to this connector the classic N+1 issue arrises where N queries need to be performed for N records in a relationship.
For example if you distributed the chinook dataset across two postgres instances with one fronted by the PG connector and one fronted by a HasuraV2 instance and the GraphQL connector:
- Subgraph 1
- Subgraph 2
- PG
- HasuraV2
- GraphQL Connector
Then querying across the relationship like so, if there were 100 albums:
query {
sg1_albums {
title
artist {
name
}
}
}
would query the graphQL connector 100 times.
The solution to this issue for other connectors has been to implement the ForEach capability which then allows a query against the full set of records in the relationship at once, deferring the choice of what to do to the connector.
The current implementation of the GraphQL Connector does not support the ForEach capability and associated variables. However we can't simply add this and implement an optimised query because unlike SQL databases, upstream GraphQL schemas don't share singular and plural records behind the same interface (tables), and don't indicate relationships involved between fields.
In this example, imagine that the NDC query was sent to the connector:
{
"query": {
... "table": "artist",
... "fields": ["name"]
},
"variables": [{
"artist_id": 1,
...
}]
}
We would hope that the upstream query would be something like:
query {
artists(where: {artist_id: {in: [1,...]}}) {
artist_id,
name
}
}
but how does the connector know that artists corresponds to artist and that the artist_id variable set should be put into the where: {artist_id: {in: filter.
In addition to this, once the query is performed it has to be decomposed into a resultset rather than just forward the results of the naive query.
So,
- The core issue is how to represent the relationships between fields and variables.
- A secondary issue is where to perform the translation logic.
There are many options for this, however my preference is:
- We should ideally be able to encode these relationships in the graphQL schema directly with directives
- This can then be extracted for use in queries, however it can also be added in the connector config independently of the schema
- The translation and decomposition logic should be put into the engine so that it can be reused across other connectors without each connector having to implement it
- Connectors can deliver this information to the engine via the NDC schema
- If the engine implementation isn't feasible the it can be implemented via ForEach in the GraphQL connector to solve the immediate issue and act as a proof of concept
See Also
When a remote relationship to this connector the classic N+1 issue arrises where N queries need to be performed for N records in a relationship.
For example if you distributed the chinook dataset across two postgres instances with one fronted by the PG connector and one fronted by a HasuraV2 instance and the GraphQL connector:
Then querying across the relationship like so, if there were 100 albums:
would query the graphQL connector 100 times.
The solution to this issue for other connectors has been to implement the
ForEachcapability which then allows a query against the full set of records in the relationship at once, deferring the choice of what to do to the connector.The current implementation of the GraphQL Connector does not support the ForEach capability and associated variables. However we can't simply add this and implement an optimised query because unlike SQL databases, upstream GraphQL schemas don't share singular and plural records behind the same interface (tables), and don't indicate relationships involved between fields.
In this example, imagine that the NDC query was sent to the connector:
We would hope that the upstream query would be something like:
but how does the connector know that
artistscorresponds toartistand that theartist_idvariable set should be put into thewhere: {artist_id: {in:filter.In addition to this, once the query is performed it has to be decomposed into a resultset rather than just forward the results of the naive query.
So,
There are many options for this, however my preference is:
See Also