Filtering
Hygraph automatically creates filters for types you add to your content models. These filters can be applied to a single, or multiple entries, and nested object fields.
The best place to explore all available filters is by using the API Playground.
Using filtersAnchor
To filter content entries, simply pass the where
argument to the query, followed by any of the filter types for the fields on your model.
All models come with their own custom GraphQL input type. Depending on the field type you want to filter by, there will be different fields you can filter by. String fields will behaviour differently to Boolean fields for example.
For example, a Post
model will have the where
input types PostWhereInput
and PostWhereUniqueInput
on the posts
, and postsConnection
query types. These types contain filters specific to that content type.
Filter typesAnchor
IDAnchor
Entries can be filtered by id
.
Matches | Type | Behaviour |
---|---|---|
id | ID | Equal to |
id_not | ID | Not this |
id_in | [ID!] | One of |
id_not_in | [ID!] | Not one of |
id_starts_with | ID | Starts with |
id_not_starts_with | ID | Does not start with |
id_ends_with | ID | Ends with |
id_not_ends_with | ID | Does not end with |
id_contains | ID | Contains |
id_not_contains | ID | Does not contain |
StringAnchor
All String fields can be filtered using:
Matches | Type | Behaviour |
---|---|---|
[fieldName]_not | String | Not this |
[fieldName]_in | [String] | One of |
[fieldName]_not_in | [String] | Not one of |
[fieldName]_starts_with | String | Starts with string |
[fieldName]_not_starts_with | String | Doesn't start with string |
[fieldName]_ends_with | String | Ends with string |
[fieldName]_not_ends_with | String | Doesn't end with string |
[fieldName]_contains | String | Includes string |
[fieldName]_not_contains | String | Does not include string |
IntegerAnchor
All Integer fields can be filtered using:
Matches | Type | Behaviour |
---|---|---|
[fieldName]_not | Int | Not this |
[fieldName]_in | [Int] | One of |
[fieldName]_not_in | [Int] | Not one of |
[fieldName]_lt | Int | Less than |
[fieldName]_gt | Int | Greater than |
[fieldName]_lte | Int | Less than or equal to |
[fieldName]_gte | Int | Greater than or equal to |
{products(where: { quantity: 100 }) {quantity}multipleQuantities: products(where: { quantity_in: [10, 100, 1000] }) {quantity}}
FloatAnchor
All Float fields can be filtered using:
Matches | Type | Behaviour |
---|---|---|
[fieldName]_not | Float | Not this |
[fieldName]_in | [Float] | One of |
[fieldName]_not_in | [Float] | Not one of |
[fieldName]_lt | Float | Less than |
[fieldName]_gt | Float | Greater than |
[fieldName]_lte | Float | Less than or equal to |
[fieldName]_gte | Float | Greater than or equal to |
{products(where: { rating: 4.5 }) {namerating}}
BooleanAnchor
All Booleans belonging to your content model can be filtered using the field name directly, as well as appended with _not
, with a Boolean input type.
Matches | Type | Behaviour |
---|---|---|
[field] | Boolean | Is |
[field]_not | Boolean | Is not |
For example, let's filter posts where the custom field verified
is true
:
{posts(where: { verified: true }) {id}posts(where: { verified_not: true }) {id}}
DateAnchor
All Date fields can be filtered using:
Matches | Type | Behaviour |
---|---|---|
[fieldName]_not | Date | Not this |
[fieldName]_in | [Date] | One of |
[fieldName]_not_in | [Date] | Not one of |
[fieldName]_lt | Date | Less than |
[fieldName]_gt | Date | Greater than |
[fieldName]_lte | Date | Less than or equal to |
[fieldName]_gte | Date | Greater than or equal to |
{today: events(where: { day: "2020-10-07" }) {day}upcoming: events(where: { day_gt: "2020-10-07" }) {day}}
DateTimeAnchor
Hygraph stores Date/DateTime fields as UTC strings, ISO 8601.
Like Date fields, DateTime fields can be filtered using:
Matches | Type | Behaviour |
---|---|---|
[fieldName]_not | DateTime | Not this |
[fieldName]_in | [DateTime] | One of |
[fieldName]_not_in | [DateTime] | Not one of |
[fieldName]_lt | DateTime | Less than |
[fieldName]_gt | DateTime | Greater than |
[fieldName]_lte | DateTime | Less than or equal to |
[fieldName]_gte | DateTime | Greater than or equal to |
{events(where: { start: "2020-10-07T09:00:00+00:00" }) {start}previous: events(where: { start_lt: "2020-10-07T09:00:00+00:00" }) {start}}
ReferenceAnchor
All relations (except Unions) can be filtered using filters on the fields of the model you are referencing. You can filter where every, some, and none at all match the conditions provided.
Matches | Behaviour |
---|---|
[fieldName]_every | Every reference matches |
[fieldName]_some | Some references match |
[fieldName]_none | No references match |
For example, you could fetch every post by the provided author name.
{posts(where: { authors_every: { name_in: ["John", "Simona"] } }) {titleauthors {name}}}
Null referencesAnchor
It is possible to filter on single, and multi reference fields for when these references are empty.
[fieldName]_every: {}
: Returns all authors, with or without connected posts[fieldName]_some: {}
: Returns all authors with at least one connected post[fieldName]_none: {}
: Returns all authors that have no posts connected
EnumerationAnchor
All Enum fields can be filtered by using:
Matches | Type | Behaviour |
---|---|---|
[fieldName]_not | EnumerationValue | Not this |
[fieldName]_in | [EnumerationValue] | One of |
[fieldName]_not_in | [EnumerationValue] | Not one of |
[fieldName]_lt | EnumerationValue | Less than |
[fieldName]_gt | EnumerationValue | Greater than |
[fieldName]_lte | EnumerationValue | Less than or equal to |
[fieldName]_gte | EnumerationValue | Greater than or equal to |
The type of enumeration you can filter by will be the actual Enumeration values defined in your schema.
{resources(where: { type_in: [Webinar, Ebook] }) {id}}
Webinar
and Ebook
are Enumeration values for field type
.
AssetAnchor
All Asset fields can be filtered using:
Matches | Type | Behaviour |
---|---|---|
[fieldName]_not | String | Not this |
[fieldName]_in | [String] | One of |
[fieldName]_not_in | [String] | Not one of |
[fieldName]_lt | String | Less than |
[fieldName]_gt | String | Greater than |
[fieldName]_lte | String | Less than or equal to |
[fieldName]_gte | String | Greater than or equal to |
[fieldName]_every | Relation Type | Every reference matches |
[fieldName]_some | Relation Type | Some references match |
[fieldName]_none | Relation Type | No references match |
Asset fields come with their own System Fields which you can apply these filters on, as well as any custom fields, or references you add.
You can filter the asset through the reference, or when querying all assets.
For example, we could fetch posts where the coverImage
field meets the provided criteria on the systme field fileName
:
{posts(where: { coverImage: { fileName: "image.png" } }) {idcoverImage {fileName}}}
Combining filtersAnchor
Just like combining query arguments, it is also possible to combine filters.
{events(where: {start_gt: "2020-10-01T09:00:00+00:00"start_lt: "2020-10-31T09:00:00+00:00"fancyDress: trueprice: 100}) {startfancyDressprice}previous: events(where: { start_lt: "2020-10-07T09:00:00+00:00" }) {start}}
Conditional filtersAnchor
Hygraph supports conditional filters for your content using AND
, NOT
and OR
. Useful for filtering results basd on more than one criteria.
Conditional filters are a way to logically apply conditions of the applicable filters above. They can also be nested.
Input Type | Description |
---|---|
AND | Fetch entires that meet both conditions. |
OR | Fetch entries that match either condition. |
NOT | Fetch all entries where the conditions do not match. |
Filter by localesAnchor
When querying content entries, you can also filter by locales
:
{posts(locales: [en]) {id}}
Learn more about localization.
Filter by stage argumentAnchor
When querying content entries, you can also filter by stage
. The stage argument decides what document variation gets returned and searched through. Therefore, if the document does not exist in the stage variation, it gets filtered out.
{posts(stage: PUBLISHED) {idstage}}
Learn more about content stages.
Filter by content stageAnchor
Stages work a bit differently in the API than in the UI. In the UI, we use the most intuitive and editor-friendly way of treating filters. So, for instance, if you see a green PUBLISHED
pill next to an entry, then this entry is only in the PUBLISHED
stage. However, in the backend, our stages are organized slightly differently. The main difference is that each content entry always exists in DRAFT
, and other stages are added or removed. For example, an entry that has a green PUBLISHED
pill in the UI is actually in both DRAFT
and PUBLISHED
stages on the API side, and both versions of the entry are identical. If you update the DRAFT
version but don't publish it, the entry will continue to exist in both stages, but will be marked as blue PUBLISHED
in the UI.
Stages can be filtered using:
Matches | Behaviour |
---|---|
documentInStages_every | All existing stage variations must match the sub-filter |
documentInStages_some | At least one of the existing stage variations must match the sub-filter |
documentInStages_none | None of the existing stage variations are allowed to match the sub-filter |
To summarize, like we mentioned before, a document will always exist in the DRAFT
stage, and they may or may not exist in other published stages such as PUBLISHED
or for example QA
- which is a custom content stage that can be published to.
If you, as a user, want to find documents that exist in the PUBLISHED
stage, you can run the following query:
stage: DRAFTwhere: {documentInStages_some: {stage: PUBLISHED}}
The above documentInStages_some
allows the user to find documents which exist in a different stage. Let's consider the following 3 documents, which exist in the following stages:
ID | STAGES |
---|---|
cldocument1 | [DRAFT, PUBLISHED] |
cldocument2 | [DRAFT] |
cldocument4 | [DRAFT, PUBLISHED, QA] |
The above query will return documents that also exist in the PUBLISHED
stage, which are cldocument1
and cldocument4
.
However you may have noticed that cldocument4
also has been published to the QA
stage - If you have access to custom stages.
Imagine you want to query documents which exist only in one published stage PUBLISHED
, but not any other publishable stages. In this case the result you want is cldocument1
. For this we can use documentInStages_every
.
Keeping in mind that a document entry can exist in multiple stages, the difference between documentInStages_some
and documentInStages_every
is that documentInStages_some
checks if an entry exists in a particular stage, whereas by using documentInStages_every
we request an entry that exists in only and exactly that stage. So if we use documentInStages_every
with PUBLISHED
the query will return results only if the document exists in PUBLISHED
and no other stage.
You might read this and try a query such as the following:
where: {documentInStages_every: {stage: PUBLISHED}}
While you are on the right track, this will unfortunately return no results. The reason is that, as we mentioned earlier, every document always exists in DRAFT
, so no document will ever only exist in PUBLISHED
.
If you try changing the above PUBLISHED
to DRAFT
, however, you will get cldocument2
as a result, as this document only exists in the DRAFT
stage.
As a workaround for this problem, we can use the OR
meta filter, by using the following query:
where: {documentInStages_every: {OR: [{stage: DRAFT},{stage: PUBLISHED}]}}
Since the internal query is that the stage must exist either in DRAFT
or PUBLISHED
, the query evaluates to true for both document cldocument1
and cldocument2
. It skips cldocument4
, which is what we want, but we still get cldocument2
which exists only in DRAFT
.
We can use the same pattern of using meta filters to filter out the DRAFT
entry. Let's start by writing this query:
where: {NOT: [{documentInStages_every: {stage: DRAFT}}]}
As you can see, this query returns any document that does not exist only in DRAFT
, Which in this case would be cldocument1
and cldocument4
. If we were to do an intersection of the results of the above two queries, we would get cldocument1
, which is the document that we want.
In order to do this, we combine the above two queries to create the following:
where: {AND: [{documentInStages_every: {OR: [{stage: DRAFT},{stage: PUBLISHED}]}},{NOT: [{documentInStages_every: {stage: DRAFT}}]}]}
As you can see above, by using the AND
meta filter we get the intersection between the two queries above, which returns the cldocument1
document.
compareWithParent
compareWithParent
allows the comparison of a document with its parent entry using any comparison operators available within it.
At the moment compareWithParent
is available only inside a documentInStages_*
filter, and only allows the use of one attribute which is outdated_to
. This attribute can be found inside the compareWithParent
filter. The attribute is used to specify if we wish to check whether the child document is outdated compared to the parent document. For example:
variousDocuments(stage: DRAFTwhere: {documentInStages_some: {stage: PUBLISHEDcompareWithParent: {outdated_to: true}}})
In the above example, we enable the filter by setting outdated_to
to true - if it were set to false, it would be the same as having the filter omitted entirely. The true and false values are simply indicators of whether to process the filter in the query.
In the above query, we check if the child PUBLISHED
version is outdated compared to the DRAFT
parent version. At the moment, we check if a document is outdated by comparing the updatedAt
attributes of both the DRAFT
and PUBLISHED
versions. If the DRAFT
has a greater updatedAt
, that means the document has been modified since it was last published, and is therefore considered outdated.