How can I query for the following object?
{
result: {
'1': {
^^^ these are dynamic keys, never constant
id: 'id1',
},
'20': {
id: 'id2',
},
'300': {
id: 'id3',
},
}
}
I know that I can define the result
object fairly simply, if it wasn’t a key-value pair object.
const ResultQueryType = new GraphQLObjectType({
name: 'ResultQueryType',
fields: () => ({
id: { type: GraphQLString }
})
})
But this is clearly not what I need. I haven’t encountered such a scenario with GraphQL yet, what can I do here?
3 Answers
You can try the dynamic key as suggested here. https://graphql.org/graphql-js/type/#graphqlobjecttype
const ResultQueryType = new GraphQLObjectType({
name: "ResultQueryType",
fields: () => ({
[fieldName: string]: { type: GraphQLString },
}),
});
You can only query fields that have been explicitly defined in the schema.
Spec: The target field of a field selection must be defined on the scoped type of the selection set.
Docs Every GraphQL service defines a set of types which completely describe the set of possible data you can query on that service. Then, when queries come in, they are validated and executed against that schema.
In other words, you can’t have a Results
map type (and therefore can’t query it) if its fields are not known to the schema definition. There are a couple of workarounds:
- Use JSON. Many implementations let you define custom scalars as JSON or
have aJSON
type that is aString
alias. You keep the map structure but lose type awareness. It’s left to the client to parse the result. - Refactor your map to an array. If you can merge the top-level key into each record, you can return an
[Item]
array.
You have to abandon the map, but you keep full GraphQL type-awareness.
I had a similar issue and decided to make my life easier by converting my result object to an array that GraphQL could easily understand.
Define an input type
input MyKeyValue {
key: String
value: String
}
Then add an array param of it to your query
query Query($keyValues: [MyKeyValue]) {
MyGraphQlQuery(keyValues: $keyValues) ..
}
Now in your code you have to format your result object to match the input definition, e.g in javascript
const results = Object.keys(result).map((key) => ({
key,
value: result[key].id
}));
which will give you an array that will look like
[{ key: '1', value: 'id1' }, ...]
and then however you call your query set $keyValues
to results
and your query will have all your result data.