Filtering
Filter by Exact Value
Use _eq to match items where a field equals a specific value.
Return all published articles:
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'status'],
filter: { status: { _eq: 'published' } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title,status" \
--data-urlencode "filter[status][_eq]=published"
const response = await fetch(
'https://example.monospace.io/api/blog/items/articles?fields=id,title,status&filter[status][_eq]=published',
{
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
},
);
const { data } = await response.json();
{ _eq: value }. This works in both REST (filter[status]=published) and the SDK (filter: { status: 'published' }). See Type System for typed shorthand.Compare with Greater Than / Less Than
Use _gt, _gte, _lt, and _lte to compare numeric, date, or string values.
Return articles with more than 1000 words:
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'word_count'],
filter: { word_count: { _gt: 1000 } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title,word_count" \
--data-urlencode "filter[word_count][_gt]=1000"
const response = await fetch(
'https://example.monospace.io/api/blog/items/articles?fields=id,title,word_count&filter[word_count][_gt]=1000',
{
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
},
);
const { data } = await response.json();
These operators also work with dates (passed as ISO 8601 strings through string filters). Return articles published after January 1, 2026:
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'published_at'],
filter: { published_at: { _gte: '2026-01-01' } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title,published_at" \
--data-urlencode "filter[published_at][_gte]=2026-01-01"
const response = await fetch(
'https://example.monospace.io/api/blog/items/articles?fields=id,title,published_at&filter[published_at][_gte]=2026-01-01',
{
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
},
);
const { data } = await response.json();
Check if a Value is Between Two Bounds
Use _between to match values within an inclusive range. Pass two values as the lower and upper bound. Use _nbetween to match values outside the range.
Return articles with a word count between 500 and 2000:
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'word_count'],
filter: { word_count: { _between: [500, 2000] } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title,word_count" \
--data-urlencode "filter[word_count][_between][0]=500" \
--data-urlencode "filter[word_count][_between][1]=2000"
const url = new URL('https://example.monospace.io/api/blog/items/articles');
url.searchParams.set('fields', 'id,title,word_count');
url.searchParams.set('filter[word_count][_between][0]', '500');
url.searchParams.set('filter[word_count][_between][1]', '2000');
const response = await fetch(url, {
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
});
const { data } = await response.json();
Exclude articles in that range with _nbetween:
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'word_count'],
filter: { word_count: { _nbetween: [500, 2000] } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title,word_count" \
--data-urlencode "filter[word_count][_nbetween][0]=500" \
--data-urlencode "filter[word_count][_nbetween][1]=2000"
const url = new URL('https://example.monospace.io/api/blog/items/articles');
url.searchParams.set('fields', 'id,title,word_count');
url.searchParams.set('filter[word_count][_nbetween][0]', '500');
url.searchParams.set('filter[word_count][_nbetween][1]', '2000');
const response = await fetch(url, {
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
});
const { data } = await response.json();
Check if a Value is in a List
Use _in to match any value in a set. Use _nin to exclude values in a set.
Return articles that are either published or featured:
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'status'],
filter: { status: { _in: ['published', 'featured'] } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title,status" \
--data-urlencode "filter[status][_in][0]=published" \
--data-urlencode "filter[status][_in][1]=featured"
const url = new URL('https://example.monospace.io/api/blog/items/articles');
url.searchParams.set('fields', 'id,title,status');
url.searchParams.set('filter[status][_in][0]', 'published');
url.searchParams.set('filter[status][_in][1]', 'featured');
const response = await fetch(url, {
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
});
const { data } = await response.json();
Exclude draft and archived articles:
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'status'],
filter: { status: { _nin: ['draft', 'archived'] } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title,status" \
--data-urlencode "filter[status][_nin][0]=draft" \
--data-urlencode "filter[status][_nin][1]=archived"
const url = new URL('https://example.monospace.io/api/blog/items/articles');
url.searchParams.set('fields', 'id,title,status');
url.searchParams.set('filter[status][_nin][0]', 'draft');
url.searchParams.set('filter[status][_nin][1]', 'archived');
const response = await fetch(url, {
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
});
const { data } = await response.json();
Search Text with Contains
Use _contains for case-sensitive substring matching and _icontains for case-insensitive. Use _ncontains and _nicontains to negate.
Return articles with "TypeScript" in the title:
const articles = await client.Articles.readMany({
fields: ['id', 'title'],
filter: { title: { _contains: 'TypeScript' } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title" \
--data-urlencode "filter[title][_contains]=TypeScript"
const response = await fetch(
'https://example.monospace.io/api/blog/items/articles?fields=id,title&filter[title][_contains]=TypeScript',
{
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
},
);
const { data } = await response.json();
Case-insensitive search for "graphql" in any casing:
const articles = await client.Articles.readMany({
fields: ['id', 'title'],
filter: { title: { _icontains: 'graphql' } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title" \
--data-urlencode "filter[title][_icontains]=graphql"
const response = await fetch(
'https://example.monospace.io/api/blog/items/articles?fields=id,title&filter[title][_icontains]=graphql',
{
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
},
);
const { data } = await response.json();
Exclude articles containing "Draft":
const articles = await client.Articles.readMany({
fields: ['id', 'title'],
filter: { title: { _ncontains: 'Draft' } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title" \
--data-urlencode "filter[title][_ncontains]=Draft"
const response = await fetch(
'https://example.monospace.io/api/blog/items/articles?fields=id,title&filter[title][_ncontains]=Draft',
{
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
},
);
const { data } = await response.json();
Search Text with Starts With / Ends With
Use _starts_with and _ends_with to match the beginning or end of a string. Use _nstarts_with and _nends_with to negate.
Return articles with a slug starting with "2026-":
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'slug'],
filter: { slug: { _starts_with: '2026-' } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title,slug" \
--data-urlencode "filter[slug][_starts_with]=2026-"
const response = await fetch(
'https://example.monospace.io/api/blog/items/articles?fields=id,title,slug&filter[slug][_starts_with]=2026-',
{
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
},
);
const { data } = await response.json();
Exclude authors with a test email domain:
const authors = await client.Authors.readMany({
fields: ['id', 'name', 'email'],
filter: { email: { _nends_with: '@test.com' } },
});
curl https://example.monospace.io/api/blog/items/authors \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,name,email" \
--data-urlencode "filter[email][_nends_with]=@test.com"
const response = await fetch(
'https://example.monospace.io/api/blog/items/authors?fields=id,name,email&filter[email][_nends_with]=@test.com',
{
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
},
);
const { data } = await response.json();
Negate a Filter
Use _not to negate a filter condition. _not accepts a single filter object (not an array).
Return articles that are not in draft status:
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'status'],
filter: {
_not: { status: { _eq: 'draft' } },
},
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title,status" \
--data-urlencode "filter[_not][status][_eq]=draft"
const url = new URL('https://example.monospace.io/api/blog/items/articles');
url.searchParams.set('fields', 'id,title,status');
url.searchParams.set('filter[_not][status][_eq]', 'draft');
const response = await fetch(url, {
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
});
const { data } = await response.json();
Combine Conditions with AND (Implicit)
Place multiple conditions at the top level of the filter object. All conditions must be true for an item to match — multiple keys at the same level are automatically combined with AND.
Return published articles by a specific author:
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'status'],
filter: { status: 'published', author_id: 5 },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title,status" \
--data-urlencode "filter[status][_eq]=published" \
--data-urlencode "filter[author_id][_eq]=5"
const url = new URL('https://example.monospace.io/api/blog/items/articles');
url.searchParams.set('fields', 'id,title,status');
url.searchParams.set('filter[status][_eq]', 'published');
url.searchParams.set('filter[author_id][_eq]', '5');
const response = await fetch(url, {
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
});
const { data } = await response.json();
This implicit AND is convenient for simple cases where you filter on different fields. For more complex boolean logic — such as multiple conditions on the same field, or combining AND with OR — use explicit _and.
Combine Conditions with AND (Explicit)
Use _and when you need to express complex boolean logic that implicit AND cannot cover. _and takes an array of filter objects, all of which must match.
Return articles that are both published and have more than 1000 words:
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'status', 'word_count'],
filter: {
_and: [
{ status: 'published' },
{ word_count: { _gt: 1000 } },
],
},
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title,status,word_count" \
--data-urlencode "filter[_and][0][status][_eq]=published" \
--data-urlencode "filter[_and][1][word_count][_gt]=1000"
const url = new URL('https://example.monospace.io/api/blog/items/articles');
url.searchParams.set('fields', 'id,title,status,word_count');
url.searchParams.set('filter[_and][0][status][_eq]', 'published');
url.searchParams.set('filter[_and][1][word_count][_gt]', '1000');
const response = await fetch(url, {
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
});
const { data } = await response.json();
Explicit _and is especially useful when nesting inside an _or to build compound conditions (see Nest AND and OR Conditions).
Combine Conditions with OR
Use _or to match items that satisfy at least one condition.
Return articles that are published or featured:
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'status'],
filter: {
_or: [
{ status: 'published' },
{ status: 'featured' },
],
},
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title,status" \
--data-urlencode "filter[_or][0][status][_eq]=published" \
--data-urlencode "filter[_or][1][status][_eq]=featured"
const url = new URL('https://example.monospace.io/api/blog/items/articles');
url.searchParams.set('fields', 'id,title,status');
url.searchParams.set('filter[_or][0][status][_eq]', 'published');
url.searchParams.set('filter[_or][1][status][_eq]', 'featured');
const response = await fetch(url, {
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
});
const { data } = await response.json();
Nest AND and OR Conditions
Combine _and and _or for complex logic. Each can contain the other.
Return articles that are either (published by author 5) or (featured with more than 2000 words):
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'status', 'word_count'],
filter: {
_or: [
{
_and: [
{ status: 'published' },
{ author_id: 5 },
],
},
{
_and: [
{ status: 'featured' },
{ word_count: { _gt: 2000 } },
],
},
],
},
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title,status,word_count" \
--data-urlencode "filter[_or][0][_and][0][status][_eq]=published" \
--data-urlencode "filter[_or][0][_and][1][author_id][_eq]=5" \
--data-urlencode "filter[_or][1][_and][0][status][_eq]=featured" \
--data-urlencode "filter[_or][1][_and][1][word_count][_gt]=2000"
const url = new URL('https://example.monospace.io/api/blog/items/articles');
url.searchParams.set('fields', 'id,title,status,word_count');
url.searchParams.set('filter[_or][0][_and][0][status][_eq]', 'published');
url.searchParams.set('filter[_or][0][_and][1][author_id][_eq]', '5');
url.searchParams.set('filter[_or][1][_and][0][status][_eq]', 'featured');
url.searchParams.set('filter[_or][1][_and][1][word_count][_gt]', '2000');
const response = await fetch(url, {
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
});
const { data } = await response.json();
Filter by Related Item Properties
Filter items based on a to-one related item's fields. Nest the related collection's field conditions inside the relation field name.
null where the type says it cannot.Return articles written by an author named "Jane":
const articles = await client.Articles.readMany({
fields: ['id', 'title'],
filter: { author: { name: { _eq: 'Jane' } } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title" \
--data-urlencode "filter[author][name][_eq]=Jane"
const response = await fetch(
'https://example.monospace.io/api/blog/items/articles?fields=id,title&filter[author][name][_eq]=Jane',
{
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
},
);
const { data } = await response.json();
You can chain multiple levels deep:
const comments = await client.Comments.readMany({
fields: ['id', 'body'],
filter: { article: { author: { name: { _eq: 'Jane' } } } },
});
curl https://example.monospace.io/api/blog/items/comments \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,body" \
--data-urlencode "filter[article][author][name][_eq]=Jane"
const response = await fetch(
'https://example.monospace.io/api/blog/items/comments?fields=id,body&filter[article][author][name][_eq]=Jane',
{
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
},
);
const { data } = await response.json();
Filter To-Many Relations with Quantifiers
Use _some, _none, and _every to control how a to-many relation is evaluated.
_some— at least one related item matches_none— no related items match_every— all related items match
Return articles that have at least one tag named "TypeScript":
const articles = await client.Articles.readMany({
fields: ['id', 'title'],
filter: { tags: { _some: { name: { _eq: 'TypeScript' } } } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title" \
--data-urlencode "filter[tags][_some][name][_eq]=TypeScript"
const response = await fetch(
'https://example.monospace.io/api/blog/items/articles?fields=id,title&filter[tags][_some][name][_eq]=TypeScript',
{
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
},
);
const { data } = await response.json();
Return articles with no flagged comments:
const articles = await client.Articles.readMany({
fields: ['id', 'title'],
filter: { comments: { _none: { flagged: { _eq: true } } } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title" \
--data-urlencode "filter[comments][_none][flagged][_eq]=true"
const response = await fetch(
'https://example.monospace.io/api/blog/items/articles?fields=id,title&filter[comments][_none][flagged][_eq]=true',
{
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
},
);
const { data } = await response.json();
Return articles where every tag is approved:
const articles = await client.Articles.readMany({
fields: ['id', 'title'],
filter: { tags: { _every: { approved: { _eq: true } } } },
});
curl https://example.monospace.io/api/blog/items/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "fields=id,title" \
--data-urlencode "filter[tags][_every][approved][_eq]=true"
const response = await fetch(
'https://example.monospace.io/api/blog/items/articles?fields=id,title&filter[tags][_every][approved][_eq]=true',
{
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
},
);
const { data } = await response.json();
_some.Operator Reference
Comparison Operators
| Operator | Description | Applies To | Example Value |
|---|---|---|---|
_eq | Equal to | All types | 'published' |
_neq | Not equal to | All types | 'draft' |
_gt | Greater than | String, Number | 1000 |
_gte | Greater than or equal to | String, Number | 500 |
_lt | Less than | String, Number | 2000 |
_lte | Less than or equal to | String, Number | 1500 |
_in | In a set of values | String, Number, UUID | ['published', 'featured'] |
_nin | Not in a set of values | String, Number, UUID | ['draft', 'archived'] |
_between | Between two values (inclusive) | Number | [500, 2000] |
_nbetween | Not between two values | Number | [500, 2000] |
String Operators
| Operator | Description | Example Value |
|---|---|---|
_contains | Contains substring (case-sensitive) | 'TypeScript' |
_ncontains | Does not contain substring | 'Draft' |
_icontains | Contains substring (case-insensitive) | 'graphql' |
_nicontains | Does not contain substring (case-insensitive) | 'test' |
_starts_with | Starts with | '2026-' |
_nstarts_with | Does not start with | 'test-' |
_ends_with | Ends with | '@example.com' |
_nends_with | Does not end with | '@test.com' |
Logical Operators
| Operator | Description | Value Type |
|---|---|---|
_and | All conditions must match | Array of filter objects |
_or | At least one condition must match | Array of filter objects |
_not | Negate the condition | Single filter object |
Relational Quantifiers (To-Many Only)
| Operator | Description | Value Type |
|---|---|---|
_some | At least one related item matches | Filter object |
_none | No related items match | Filter object |
_every | All related items match | Filter object |
Related pages:
- Reading Data — fetch items with sorting, pagination, and field selection
- Writing Data — use filters in
updateManyanddeleteManyoperations - Field Selection — control which fields are returned