How to represent a map or object with key-value pairs in GraphQL?

How to represent a map or object with key-value pairs in GraphQL?


2

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
3


1

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 },
  }),
});


0

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:

  1. Use JSON. Many implementations let you define custom scalars as JSON or
    have a JSON type that is a String alias. You keep the map structure but lose type awareness. It’s left to the client to parse the result.
  2. 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.


0

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.



Leave a Reply

Your email address will not be published. Required fields are marked *