Skip to main content

Filtering & Querying

TrackVision provides powerful filtering capabilities through query parameters and filter rules. This page covers all aspects of filtering data including query parameters, filter operators, and advanced filtering techniques.

Filter Parameter

The filter parameter is used to search items in a collection that match specific conditions. Filters use a JSON structure to define rules that can be flat, relational, or complex with logical operators.

Filter Syntax

{
<field>: {
<operator>: <value>
}
}

Examples

Retrieve all products where product_name equals "Organic Apple Juice"

{
"product_name": {
"_eq": "Organic Apple Juice"
}
}

Retrieve all products with a GTIN matching one of a specific set

{
"gtin": {
"_in": ["09521234543217", "09521234543224", "09521234543231"]
}
}

Retrieve all products created between two dates

{
"date_created": {
"_between": ["2024-01-01", "2024-03-31"]
}
}
?filter[product_name][_eq]=Organic Apple Juice

// or

?filter={ "product_name": { "_eq": "Organic Apple Juice" }}

Filter Operators

Operator Title (in app)OperatorDescription
Equals_eqEqual to
Doesn't equal_neqNot equal to
Less than_ltLess than
Less than or equal to_lteLess than or equal to
Greater than_gtGreater than
Greater than or equal to_gteGreater than or equal to
Is one of_inMatches any of the values
Is not one of_ninDoesn't match any of the values
Is null_nullIs null
Isn't null_nnullIs not null
Contains_containsContains the substring
Contains (case-insensitive)_icontainsContains the case-insensitive substring
Doesn't contain_ncontainsDoesn't contain the substring
Starts with_starts_withStarts with
Starts with_istarts_withStarts with, case-insensitive
Doesn't start with_nstarts_withDoesn't start with
Doesn't start with_nistarts_withDoesn't start with, case-insensitive
Ends with_ends_withEnds with
Ends with_iends_withEnds with, case-insensitive
Doesn't end with_nends_withDoesn't end with
Doesn't end with_niends_withDoesn't end with, case-insensitive
Is between_betweenIs between two values (inclusive)
Isn't between_nbetweenIs not between two values (inclusive)
Is empty_emptyIs empty (null or falsy)
Isn't empty_nemptyIs not empty (null or falsy)
Intersects_intersects [1]Value intersects a given point
Doesn't intersect_nintersects [1]Value does not intersect a given point
Intersects Bounding box_intersects_bbox [1]Value is in a bounding box
Doesn't intersect bounding box_nintersects_bbox [1]Value is not in a bounding box

The following operator has no Title on the Filter Interface as it is only available in validation permissions:

OperatorDescription
_regex [2]Field has to match regex

[1] Only available on Geometry types.
[2] JavaScript "flavor" regex. Make sure to escape backslashes.

Relational Filters

You can filter based on related data by nesting field names. This works for both Many-to-One and Many-to-Many relationships.

Many-to-One Example

Filter products where the related brand name equals "TrackVision Premium":

{
"brand": {
"brand_name": {
"_eq": "TrackVision Premium"
}
}
}

Many-to-Many Example

When using M2M relationships, filters apply through the junction table. For a product collection with M2M relationship to certifications:

{
"certifications": {
"certification_id": {
"certification_type": {
"_eq": "organic"
}
}
}
}
Nested Filters

The filter will apply to the top level items based on conditions in related items. To filter the related items themselves, use the deep parameter!

Filtering M2A Fields

For Many-to-Any fields in GraphQL, replace the : character with double underscores:

query {
product(
filter: {
related_content: {
item__documents: { # Instead of: item:documents
title: { _eq: "Safety Data Sheet" }
}
}
}
) {
id
}
}

Logical Operators

Group multiple filter rules using _and or _or logical operators. Each operator holds an array of filter rules.

Retrieve products created by the current user that are in draft, or products created by others that are active:

{
"_or": [
{
"_and": [
{
"user_created": {
"_eq": "$CURRENT_USER"
}
},
{
"status": {
"_in": ["active", "draft"]
}
}
]
},
{
"_and": [
{
"user_created": {
"_neq": "$CURRENT_USER"
}
},
{
"status": {
"_in": ["active"]
}
}
]
}
]
}

Some vs None in One-to-Many

By default, one-to-many filters use "some" logic. Override this with explicit _some and _none operators:

Fetch all products that have no certifications of type "organic":

{
"certifications": {
"_none": {
"certification_type": {
"_eq": "organic"
}
}
}
}

This fetches all products that don't have an organic certification.

Dynamic Variables

Filter against dynamic values using these variables:

  • $CURRENT_USER — The primary key of the currently authenticated user
  • $CURRENT_ROLE — The primary key of the role for the currently authenticated user
  • $CURRENT_ROLES — An array of roles containing the $CURRENT_ROLE and any roles included within it
  • $CURRENT_POLICIES — An array of policies assigned to the user directly, or through their roles
  • $NOW — The current timestamp
  • $NOW(<adjustment>) — The current timestamp plus/minus a given distance, e.g., $NOW(-1 year), $NOW(+2 hours)
Nested User/Role Variables

In permissions, $CURRENT_USER and $CURRENT_ROLE allow specifying nested fields: $CURRENT_ROLE.name or $CURRENT_USER.avatar.filesize. This includes custom fields added to trackvision_users/trackvision_roles tables.

Note: Regular filters only support the root ID.

Other Query Parameters

Most TrackVision native API endpoints support these query parameters for filtering and manipulating data:

Fields

Choose which fields to return in the response. Supports dot notation for nested relational fields and wildcards (*).

Examples

Get all top-level fields:
*

Get all top-level fields and all second-level relational fields:
*.*

Get specific fields: product_name,gtin

Get nested relational data: *,brand.*

Many-To-Any Fields

For M2A fields, specify fields per collection type: ?fields=<m2a-field>:<collection-scope>.<field>

Example for a product collection with related_content pointing to different content types:

GET /items/product
?fields[]=product_name
&fields[]=related_content.item:documents.title
&fields[]=related_content.item:documents.file
&fields[]=related_content.item:videos.source
Performance

For production use, request only specific fields instead of wildcards to improve performance and reduce response size.

Perform text search across textual and numeric fields in a collection. Only searches root item fields.

?search=Organic

Sort

Sort results by field(s). Use - prefix for descending order. Supports dot notation for nested fields.

Examples:

  • Sort by creation date descending: -date_created
  • Multiple sorts: product_name,-date_created
  • Nested field sort: brand.brand_name
?sort=product_name,-date_created,brand.brand_name

// or

?sort[]=product_name&sort[]=-date_created&sort[]=brand.brand_name

Limit

Set maximum items returned (default: 100).

?limit=200

Maximum Items

Use -1 for maximum allowed items. Large requests may cause performance issues. Configure max with QUERY_LIMIT_MAX.

Offset

Skip the first n items. Used for pagination.

?offset=100

Page

Alternative to offset. Sets offset as limit * page. Page is 1-indexed.

?page=2

Advanced Features

Deep Filtering

Apply query parameters to nested relational datasets using the deep parameter.

Limit nested certifications on a product to 3:

{
"certifications": {
"_limit": 3
}
}

Complex nested filtering — limit certifications and sort lots by expiry date:

{
"certifications": {
"_limit": 3,
"lots": {
"_sort": "expiry_date",
"_limit": 1
}
}
}

Filter product translations to return only the English version:

?deep[translations][_filter][languages_code][_eq]=en-US

// or

?deep={ "translations": { "_filter": { "languages_code": { "_eq": "en-US" }}}}

Aliases

Rename fields on the fly and request the same nested dataset multiple times with different filters.

Request both all translations and only the French translation of a product in a single call:

?alias[all_translations]=translations
&alias[french_translations]=translations
&deep[french_translations][_filter][languages_code][_eq]=fr-FR
Nested Fields

Aliases only work for same-level fields. Cannot alias nested fields like field.nested.

Aggregation & Grouping

Perform calculations on sets of values:

FunctionDescription
countCount items
countDistinctCount unique items
sumSum values
sumDistinctSum unique values
avgAverage value
avgDistinctAverage of unique values
minMinimum value
maxMaximum value
countAllCount all (GraphQL only)

Grouping

Group aggregations by field values for reporting like "Number of products per brand per year":

?aggregate[count]=id,gtin
&groupBy[]=brand
&groupBy[]=year(date_created)

Functions

Apply functions to transform field values in queries:

DateTime Functions

FunctionDescription
yearExtract year
monthExtract month
weekExtract week
dayExtract day
weekdayExtract weekday
hourExtract hour
minuteExtract minute
secondExtract second

Array Functions

FunctionDescription
countCount items in array/relation
?fields=id,product_name,month(date_created)
&filter[year(date_created)][_eq]=2024

Export

Save API responses to file formats:

?export=csv
?export=json
?export=xml
?export=yaml