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:

type FriendlyUser {
sys: Sys
name: String
age: Integer
}

The schema defines the following filter input type:

input FriendlyUserFilter {
sys: SysFilter
contentfulMetadata: ContentfulMetadataFilter
name: String
name_not: String
name_exists: Boolean
name_contains: String
# ... more name filters
age: Number
age_gt: Number
age_lt: Number
# ... more age filters
AND: [FriendlyUserFilter]
OR: [FriendlyUserFilter]
}

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:

query {
friendlyUserCollection(where: {
AND: [
{
OR: [
{ name: "Frank" },
{ name: "Francine" }
]
},
{ age_gt: 30 }
],
}) {
name
age
}
}

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:

query {
friendlyUserCollection(where: {
OR: [
{ name: "Hans" },
{ name: "Joe" }
]
age_gte: 30,
age_lte: 40
}) { name }
}

And result in the following equivalent query:

query {
friendlyUserCollection(where: {
AND: [
OR: [
{ name: "Hans" },
{ name: "Joe" }
],
{ age_gte: 30 },
{ age_lte: 40 }
]
}) { name }
}

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:

type FriendlyUser {
# ... other fields
name: String
}
input FriendlyUserFilter {
# ... other field filters
# Matches if the field is equal to the given value
name: String
# Matches if the field is not equal to the given value
name_not: String
# Matches if the field exists
name_exists: Boolean
# Matches if the field value equal one of the given values
name_in: [String]
# Matches if the field value does not equal any of the given values
name_not_in: [String]
# Matches if given value is a substring of the field value
name_contains: String
# Matches if given value is not a substring of the field value
name_not_contains: String
}

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:

type FriendlyUser {
# ... other fields
age: Int
}
input FriendlyUserFilter {
# ... other field filters
# Matches if the field is equal to the given value
age: Int
# Matches if the field is not equal to the given value
age_not: Int
# Matches if the field exists
age_exists: Boolean
# Matches if the field value equal one of the given values
age_in: [Int]
# Matches if the field value does not equal any of the given values
age_not_in: [Int]
# Matches if the field value is strictly smaller than the given value
age_lt: Int
# Matches if the field value is smaller than or equal to the given value
age_lte: Int
# Matches if the field value is strictly greater than the given value
age_gt: Int
# Matches if the field value is greater than or equal to the given value
age_gte: Int
}

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:

type FriendlyUser {
# ... other fields
employed: Boolean
}
input FriendlyUserFilter {
# ... other field filters
# Matches if the field is equal to the given value
employed: Boolean
# Matches if the field is not equal to the given value
employed_not: Boolean
# Matches if the field exists
employed_exists: Boolean
}

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:

type FriendlyUser {
# ... other fields
birthday: DateTime
}
input FriendlyUserFilter {
# ... other field filters
# Matches if the field is equal to the given value
birthday: DateTime
# Matches if the field is not equal to the given value
birthday_not: DateTime
# Matches if the field exists
birthday_exists: Boolean
# Matches if the field value equal one of the given values
birthday_in: [DateTime]
# Matches if the field value does not equal any of the given values
birthday_not_in: [DateTime]
# Matches if the field value is strictly smaller than the given value
birthday_lt: DateTime
# Matches if the field value is smaller than or equal to the given value
birthday_lte: DateTime
# Matches if the field value is strictly greater than the given value
birthday_gt: DateTime
# Matches if the field value is greater than or equal to the given value
birthday_gte: DateTime
}

Location

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

The Circle scalar type has the following format:

{
lat: 10.11,
lon: 10.11,
radius: 10,
}

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:

{
topLeftLat: 40,
topLeftLon: 13.35,
bottomRightLat: 41,
bottomRightLon: 14.36
}

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:

type FriendlyUser {
# ... other fields
place: Location
}
input FriendlyUserFilter {
# ... other field filters
# Matches if the position is inside the given circle
place_within_circle: Circle
# Matches if the position is inside the given rectangle
place_within_rectangle: Rectangle
}

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:

type FriendlyUser {
# ... other fields
nicknames: [String]
}
input FriendlyUserFilter {
# ... other field filters
# Matches if the field array contains *all* items provided to the filter
nicknames_contains_all: [String]
# Matches if the field array contains at least one item provided to the filter
nicknames_contains_some: [String]
# Matches if the field array doesn't contain any item provided to the filter
nicknames_contains_none: [String]
}

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).

type FriendlyUser {
sys: Sys
firstbornChild: Child
# ... other fields
}
type Child {
name: String
}
input FriendlyUserFilter {
sys: SysFilter
contentfulMetadata: ContentfulMetadataFilter
firstbornChild: FriendlyUserFirstbornChildFilter
# ... more filters
}
input FriendlyUserFirstbornChildFilter {
sys: SysFilter
contentfulMetadata: ContentfulMetadataFilter
name: String
name_not: String
name_exists: Boolean
name_contains: String
# ... more name filters
}

sys filters

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

input FriendlyUserFilter {
sys: SysFilter
# ... other fields
}
input SysFilter {
id: String
id_not: String
id_in: [String]
id_not_in: [String]
id_contains: String
id_not_contains: String
}

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:

query {
friendlyUserCollection(where: {
sys: {
id_in: ["id1", "id2"]
}
}) { sys { id } }
}

contentfulMetadata filters

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

input EntryCollectionFilter {
sys: SysFilter
contentfulMetadata: ContentfulMetadataFilter
}
input ContentfulMetadataFilter {
tags_exists: Boolean
tags: ContentfulMetadataTagsFilter
}
input ContentfulMetadataTagsFilter {
id_contains_some: [String!]
id_contains_none: [String!]
id_contains_all: [String!]
}

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:

query {
entryCollection(where: {
contentfulMetadata: {
tags_exists: true
tags: {
id_contains_some: ["tagId1", "tagId2"]
}
}
}) {
sys {
id
}
contentfulMetadata {
tags {
id
}
}
}
}

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.

query {
friendlyUserCollection {
items {
firstName
catCollection(where: {name: "foobar"}) {
items {
name
}
}
}
}
}

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.

query {
friendlyUserCollection {
items {
firstName
petsCollection(where: {name: "foobar"}) {
items {
__typename
... on Cat {
name
numberOfLivesLeft
}
... on Dog {
name
likesGoingForWalks
}
}
}
}
}
}

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.