Collection filters

The GraphQL Content API allows users to specify filters on root collection queries.

Collections could be filtered by different fields or combination of fields that contain collection items. There are general and type specific filters:

FilterPostfixField type
equal(none)<any scalar>
not equal_not<any scalar>
exists_exists<any>
contains_containsString, RichText
does not contain_not_containsString, RichText
greater than_gtNumber, Date
greater or equals_gteNumber, Date
less than_ltNumber, Date
less or equals_lteNumber, Date
in given list_inString, Number, Date
not in given list_not_inString, Number, Date
within circle_within_circleLocation
within rectangle_within_rectangleLocation
contains all_contains_allArray
contains some_contains_someArray
contains none_contains_noneArray

For each content type the schema defines an input type to filter entries of that content type. For example, for the type FriendlyUser structured in the following way:

1type FriendlyUser {
2 sys: Sys
3 name: String
4 age: Integer
5}

The schema defines the following filter input type:

1input FriendlyUserFilter {
2 sys: SysFilter
3 contentfulMetadata: ContentfulMetadataFilter
4 name: String
5 name_not: String
6 name_exists: Boolean
7 name_contains: String
8 # ... more name filters
9 age: Number
10 age_gt: Number
11 age_lt: Number
12 # ... more age filters
13 AND: [FriendlyUserFilter]
14 OR: [FriendlyUserFilter]
15}

Filter inputs can be passed to collection queries of their corresponding type to filter out mutations and the result set.

For example, to find all FriendlyUsers whose name is “Frank” or “Francine” and who are older than 30 years, write the following query:

1query {
2 friendlyUserCollection(where: {
3 AND: [
4 {
5 OR: [
6 { name: "Frank" },
7 { name: "Francine" }
8 ]
9 },
10 { age_gt: 30 }
11 ],
12 }) {
13 name
14 age
15 }
16}

Limitations

It is not possible to filter on fields of type Object or RichText. There’s an exemption in the case of the ContentfulMetadata type.

_contains filter is case insensitive and must be at least 2 characters long to work. The _contains filter is analogous to the [match] filter in the REST API content. Check the documentation of the [match] operator for more information about the details of full-text search in contentful.

For performance reasons it is not recommended to use the _contains filter when searching for slugs or text IDs. Please use the equality search instead.

Filter generation

Filter input types are derived from the content model, just like the output types. For each content type, one filter input type is derived. The user can pass it to the corresponding root collection query.

Each filter input type has the sys, AND, and OR fields as well as additional field type-specific filters for every field.

Name of the filter input type is derived from the output type by appending Filter to it.

Logical connectives

Each filter input type has two special fields AND and OR used to logically combine filters.

If multiple fields are specified on a filter, they get connected with an implicit AND:

1query {
2 friendlyUserCollection(where: {
3 OR: [
4 { name: "Hans" },
5 { name: "Joe" }
6 ]
7 age_gte: 30,
8 age_lte: 40
9 }) { name }
10}

And result in the following equivalent query:

1query {
2 friendlyUserCollection(where: {
3 AND: [
4 OR: [
5 { name: "Hans" },
6 { name: "Joe" }
7 ],
8 { age_gte: 30 },
9 { age_lte: 40 }
10 ]
11 }) { name }
12}

Both queries return all the friendly users between the age of 30 to 40 and are named either Hans or Joe.

Filters by field type

For each field in a content type a set of filter fields is added to the content type’s filter input type. The type of filters is determined by the field type.

Symbol and Text

GraphQL Content API does not distinguish between Symbol and Text types and generates the same filters for both.

For example, if the content type FriendlyUser has a Symbol field name, the following types are generated:

1type FriendlyUser {
2 # ... other fields
3 name: String
4}
5
6input FriendlyUserFilter {
7 # ... other field filters
8
9 # Matches if the field is equal to the given value
10 name: String
11 # Matches if the field is not equal to the given value
12 name_not: String
13 # Matches if the field exists
14 name_exists: Boolean
15 # Matches if the field value equal one of the given values
16 name_in: [String]
17 # Matches if the field value does not equal any of the given values
18 name_not_in: [String]
19 # Matches if given value is a substring of the field value
20 name_contains: String
21 # Matches if given value is not a substring of the field value
22 name_not_contains: String
23}

Number and Integer

Filter names for Integer and Number types are the same. They only differ in the input types for values. For Integer fields the value type is Int, whereas for Number fields the type is Float.

For example, if the content type FriendlyUser has an Integer field age, the following types are generated:

1type FriendlyUser {
2 # ... other fields
3 age: Int
4}
5
6input FriendlyUserFilter {
7 # ... other field filters
8
9 # Matches if the field is equal to the given value
10 age: Int
11 # Matches if the field is not equal to the given value
12 age_not: Int
13 # Matches if the field exists
14 age_exists: Boolean
15 # Matches if the field value equal one of the given values
16 age_in: [Int]
17 # Matches if the field value does not equal any of the given values
18 age_not_in: [Int]
19 # Matches if the field value is strictly smaller than the given value
20 age_lt: Int
21 # Matches if the field value is smaller than or equal to the given value
22 age_lte: Int
23 # Matches if the field value is strictly greater than the given value
24 age_gt: Int
25 # Matches if the field value is greater than or equal to the given value
26 age_gte: Int
27}

Boolean

Boolean filter accepts values of type Boolean and can only be used on fields with type Boolean.

For example, if the content type FriendlyUser has a Boolean field employed, the following types are generated:

1type FriendlyUser {
2 # ... other fields
3 employed: Boolean
4}
5
6input FriendlyUserFilter {
7 # ... other field filters
8
9 # Matches if the field is equal to the given value
10 employed: Boolean
11 # Matches if the field is not equal to the given value
12 employed_not: Boolean
13 # Matches if the field exists
14 employed_exists: Boolean
15}

Date

For fields with type Date the value types are DateTime. The value for filter should be provided as a full DateTime value in ISO-8601 format (e.g. yyyy-mm-ddThh:mm:ss:sssZ).

For example, if the content type FriendlyUser has a DateTime field birthday, the following types are generated:

1type FriendlyUser {
2 # ... other fields
3 birthday: DateTime
4}
5
6input FriendlyUserFilter {
7 # ... other field filters
8
9 # Matches if the field is equal to the given value
10 birthday: DateTime
11 # Matches if the field is not equal to the given value
12 birthday_not: DateTime
13 # Matches if the field exists
14 birthday_exists: Boolean
15 # Matches if the field value equal one of the given values
16 birthday_in: [DateTime]
17 # Matches if the field value does not equal any of the given values
18 birthday_not_in: [DateTime]
19 # Matches if the field value is strictly smaller than the given value
20 birthday_lt: DateTime
21 # Matches if the field value is smaller than or equal to the given value
22 birthday_lte: DateTime
23 # Matches if the field value is strictly greater than the given value
24 birthday_gt: DateTime
25 # Matches if the field value is greater than or equal to the given value
26 birthday_gte: DateTime
27}

Location

For fields with type Location the value types are either Circle or Rectangle.

The Circle scalar type has the following format:

1{
2 lat: 10.11,
3 lon: 10.11,
4 radius: 10,
5}

where lat and lon are coordinates of the center of the circle and radius its radius in kilometers.

The Rectangle scalar type has the following format:

1{
2 topLeftLat: 40,
3 topLeftLon: 13.35,
4 bottomRightLat: 41,
5 bottomRightLon: 14.36
6}

where topLeftLat with topLeftLon are the coordinates of the top left corner of the rectangle, and bottomRightLat with bottomRightLon are the coordinates of the bottom right corner of the rectangle.

For example, if the content type FriendlyUser has a Location field place, the following types are generated:

1type FriendlyUser {
2 # ... other fields
3 place: Location
4}
5
6input FriendlyUserFilter {
7 # ... other field filters
8
9 # Matches if the position is inside the given circle
10 place_within_circle: Circle
11 # Matches if the position is inside the given rectangle
12 place_within_rectangle: Rectangle
13}

Array

For Array fields with the value type String. The value for the filter should be an array of string values.

For example, if the content type FriendlyUser has an Array field nicknames, the following types are generated:

1type FriendlyUser {
2 # ... other fields
3 nicknames: [String]
4}
5
6input FriendlyUserFilter {
7 # ... other field filters
8
9 # Matches if the field array contains *all* items provided to the filter
10 nicknames_contains_all: [String]
11 # Matches if the field array contains at least one item provided to the filter
12 nicknames_contains_some: [String]
13 # Matches if the field array doesn't contain any item provided to the filter
14 nicknames_contains_none: [String]
15}

For Link fields with a single linkContentType validation. Filtering depth is limited to one level of relationships.

The collection filter input type has a property corresponding to the field name. The type of this input filter property has filters for all the linked fields (without nested Link fields).

1type FriendlyUser {
2 sys: Sys
3 firstbornChild: Child
4 # ... other fields
5}
6
7type Child {
8 name: String
9}
10
11input FriendlyUserFilter {
12 sys: SysFilter
13 contentfulMetadata: ContentfulMetadataFilter
14 firstbornChild: FriendlyUserFirstbornChildFilter
15 # ... more filters
16}
17
18input FriendlyUserFirstbornChildFilter {
19 sys: SysFilter
20 contentfulMetadata: ContentfulMetadataFilter
21 name: String
22 name_not: String
23 name_exists: Boolean
24 name_contains: String
25 # ... more name filters
26}

sys filters

Every filter input type has a sys property. The type of the sys filter property is the statically defined SysFilter type.

1input FriendlyUserFilter {
2 sys: SysFilter
3 # ... other fields
4}
5
6input SysFilter {
7 id: String
8 id_not: String
9 id_in: [String]
10 id_not_in: [String]
11 id_contains: String
12 id_not_contains: String
13}

Similar to other field filters the SysFilter input type is generated from the Sys output type. For each field in the Sys type, a set of corresponding filters are added to SysFilter.

The following is an example of a query for a list of entries by IDs:

1query {
2 friendlyUserCollection(where: {
3 sys: {
4 id_in: ["id1", "id2"]
5 }
6 }) { sys { id } }
7}

contentfulMetadata filters

Every filter input type has a contentfulMetadata property. The type of the contentfulMetadata filter property is the statically defined ContentfulMetadataFilter type.

1input EntryCollectionFilter {
2 sys: SysFilter
3 contentfulMetadata: ContentfulMetadataFilter
4}
5
6input ContentfulMetadataFilter {
7 tags_exists: Boolean
8 tags: ContentfulMetadataTagsFilter
9}
10
11input ContentfulMetadataTagsFilter {
12 id_contains_some: [String!]
13 id_contains_none: [String!]
14 id_contains_all: [String!]
15}

The ContentfulMetadataFilter input type is generated from the tags field in the ContentfulMetadata type and its id subfield in the ContentfulTag type.

The following is an example of a query for a list of entries across content types by tag presence and tag IDs:

1query {
2 entryCollection(where: {
3 contentfulMetadata: {
4 tags_exists: true
5 tags: {
6 id_contains_some: ["tagId1", "tagId2"]
7 }
8 }
9 }) {
10 sys {
11 id
12 }
13 contentfulMetadata {
14 tags {
15 id
16 }
17 }
18 }
19}

Nested collection filters

You can filter a multi reference field collection if the field contains a validation rule that makes it accept only specific content types.

If the reference field only accepts a single content type, then you can filter by any field on that content type.

1query {
2 friendlyUserCollection {
3 items {
4 firstName
5 catCollection(where: {name: "foobar"}) {
6 items {
7 name
8 }
9 }
10 }
11 }
12}

On the other hand, if the reference field accepts multiple content types, then you can filter by any field that is common across all of those content types.

A field is considered common if it has the same apiName (field id) and type on all content types. Consider you have the following content types:

  • Cat
    • field Name: Cat Name, field Id: name, type: text
    • field Name: Legs, field Id: legs, type: number
    • field Name: Lives Left, field id: livesLeftOfNine, type: number
  • Dog
    • field Name: Dog Name, field Id: name, type: text
    • field Name: Legs, field Id: legs, type: boolean
    • field Name: Likes Walks, field id: likesWalks, type: boolean
  • Person
    • field Name: Pets, field Id: pets, type: Reference, validations: Accept only specified entry types: Cat, Dog

On Person you will be able to query petsCollection by the fields that have the same field id and type on Cat and Dog. Per our content types definition above: the only common field is name (same field id name and type text on both collections). The field legs will not be a common field as its type differs across the content types.

1query {
2 friendlyUserCollection {
3 items {
4 firstName
5 petsCollection(where: {name: "foobar"}) {
6 items {
7 __typename
8 ... on Cat {
9 name
10 numberOfLivesLeft
11 }
12 ... on Dog {
13 name
14 likesGoingForWalks
15 }
16 }
17 }
18 }
19 }
20}

The petsCollection can be filtered by the fields common to both Cat and Dog types, such as name. It cannot be filtered by fields specific to any one content type, such as livesLeftOfNine or likesGoingForWalks.

Note: When you filter a reference field which accepts more than one content type, the complexity of your query increases by the number of content types the field can accept.