github.com/maeglindeveloper/gqlgen@v0.13.1-0.20210413081235-57808b12a0a0/docs/content/reference/field-collection.md (about) 1 --- 2 title: 'Determining which fields were requested by a query' 3 description: How to determine which fields a query requested in a resolver. 4 linkTitle: Field Collection 5 menu: { main: { parent: 'reference', weight: 10 } } 6 --- 7 8 Often it is useful to know which fields were queried for in a resolver. Having this information can allow a resolver to only fetch the set of fields required from a data source, rather than over-fetching everything and allowing gqlgen to do the rest. 9 10 This process is known as [Field Collection](https://facebook.github.io/graphql/draft/#sec-Field-Collection) — gqlgen automatically does this in order to know which fields should be a part of the response payload. The set of collected fields does however depend on the type being resolved. Queries can contain fragments, and resolvers can return interfaces and unions, therefore the set of collected fields cannot be fully determined until the type of the resolved object is known. 11 12 Within a resolver, there are several API methods available to query the selected fields. 13 14 ## CollectAllFields 15 16 `CollectAllFields` is the simplest way to get the set of queried fields. It will return a slice of strings of the field names from the query. This will be a unique set of fields, and will return all fragment fields, ignoring fragment Type Conditions. 17 18 Given the following example query: 19 20 ```graphql 21 query { 22 foo { 23 fieldA 24 ... on Bar { 25 fieldB 26 } 27 ... on Baz { 28 fieldC 29 } 30 } 31 } 32 ``` 33 34 Calling `CollectAllFields` from a resolver will yield a string slice containing `fieldA`, `fieldB`, and `fieldC`. 35 36 ## CollectFieldsCtx 37 38 `CollectFieldsCtx` is useful in cases where more information on matches is required, or the set of collected fields should match fragment type conditions for a resolved type. `CollectFieldsCtx` takes a `satisfies` parameter, which should be a slice of strings of types that the resolved type will satisfy. 39 40 For example, given the following schema: 41 42 ```graphql 43 interface Shape { 44 area: Float 45 } 46 type Circle implements Shape { 47 radius: Float 48 area: Float 49 } 50 union Shapes = Circle 51 ``` 52 53 The type `Circle` would satisfy `Circle`, `Shape`, and `Shapes` — these values should be passed to `CollectFieldsCtx` to get the set of collected fields for a resolved `Circle` object. 54 55 > Note 56 > 57 > `CollectFieldsCtx` is just a convenience wrapper around `CollectFields` that calls the later with the selection set automatically passed through from the resolver context. 58 59 ## Practical example 60 61 Say we have the following GraphQL query 62 63 ```graphql 64 query { 65 flowBlocks { 66 id 67 block { 68 id 69 title 70 type 71 choices { 72 id 73 title 74 description 75 slug 76 } 77 } 78 } 79 } 80 ``` 81 82 We don't want to overfetch our database so we want to know which field are requested. 83 Here is an example which get's all requested field as convenient string slice, which can be easily checked. 84 85 ```golang 86 func GetPreloads(ctx context.Context) []string { 87 return GetNestedPreloads( 88 graphql.GetOperationContext(ctx), 89 graphql.CollectFieldsCtx(ctx, nil), 90 "", 91 ) 92 } 93 94 func GetNestedPreloads(ctx *graphql.OperationContext, fields []graphql.CollectedField, prefix string) (preloads []string) { 95 for _, column := range fields { 96 prefixColumn := GetPreloadString(prefix, column.Name) 97 preloads = append(preloads, prefixColumn) 98 preloads = append(preloads, GetNestedPreloads(ctx, graphql.CollectFields(ctx, column.Selections, nil), prefixColumn)...) 99 } 100 return 101 } 102 103 func GetPreloadString(prefix, name string) string { 104 if len(prefix) > 0 { 105 return prefix + "." + name 106 } 107 return name 108 } 109 110 ``` 111 112 So if we call these helpers in our resolver: 113 ```golang 114 func (r *queryResolver) FlowBlocks(ctx context.Context) ([]*FlowBlock, error) { 115 preloads := getPreloads(ctx) 116 ``` 117 it will result in the following string slice: 118 ``` 119 ["id", "block", "block.id", "block.title", "block.type", "block.choices", "block.choices.id", "block.choices.title", "block.choices.description", "block.choices.slug"] 120 ```