SonicJS AI provides a powerful and flexible filtering system for querying content through the API. This guide covers all available filter operators and provides comprehensive examples.
Filters can be passed to the API in two equivalent forms:
- Bracket syntax —
filter[field][operator]=value(concise, recommended for simple queries) whereparameter — a JSON-encoded filter object (required for OR groups and complex logic)
Both forms can be combined in the same request; their conditions are combined with AND.
GET /api/content?filter[status][equals]=published
GET /api/content?filter[title][contains]=lyme&filter[status][equals]=publishedWhen the operator is omitted, it defaults to equals:
GET /api/content?filter[slug]=aboutGET /api/content?where={"and":[{"field":"status","operator":"equals","value":"published"}]}URL-encoded:
GET /api/content?where=%7B%22and%22%3A%5B%7B%22field%22%3A%22status%22%2C%22operator%22%3A%22equals%22%2C%22value%22%3A%22published%22%7D%5D%7DThe value must be exactly equal.
{
"where": {
"and": [
{
"field": "status",
"operator": "equals",
"value": "published"
}
]
}
}NULL handling:
{
"where": {
"and": [
{
"field": "deleted_at",
"operator": "equals",
"value": null
}
]
}
}The query will return all documents where the value is not equal.
{
"where": {
"and": [
{
"field": "status",
"operator": "not_equals",
"value": "draft"
}
]
}
}For numeric or date-based fields.
{
"where": {
"and": [
{
"field": "views",
"operator": "greater_than",
"value": 1000
}
]
}
}Date example:
{
"where": {
"and": [
{
"field": "created_at",
"operator": "greater_than",
"value": 1640995200000
}
]
}
}For numeric or date-based fields.
{
"where": {
"and": [
{
"field": "price",
"operator": "greater_than_equal",
"value": 99.99
}
]
}
}For numeric or date-based fields.
{
"where": {
"and": [
{
"field": "stock",
"operator": "less_than",
"value": 10
}
]
}
}For numeric or date-based fields.
{
"where": {
"and": [
{
"field": "priority",
"operator": "less_than_equal",
"value": 5
}
]
}
}Case-insensitive string search. If the value contains multiple words, all words must be present in any order.
{
"where": {
"and": [
{
"field": "title",
"operator": "like",
"value": "getting started tutorial"
}
]
}
}This will match:
- "Getting Started with Vue Tutorial"
- "Tutorial: Getting Started"
- "Started Getting Tutorial"
Must contain the value entered, case-insensitive. Simpler than like - just checks if the string is present.
{
"where": {
"and": [
{
"field": "description",
"operator": "contains",
"value": "javascript"
}
]
}
}The field value must begin with the provided value. Case-insensitive.
{
"where": {
"and": [
{
"field": "title",
"operator": "starts_with",
"value": "How to"
}
]
}
}The field value must end with the provided value. Case-insensitive.
{
"where": {
"and": [
{
"field": "slug",
"operator": "ends_with",
"value": "-guide"
}
]
}
}The value must be found within the provided comma-delimited list of values.
Array format:
{
"where": {
"and": [
{
"field": "status",
"operator": "in",
"value": ["published", "review", "scheduled"]
}
]
}
}Comma-delimited string:
{
"where": {
"and": [
{
"field": "category",
"operator": "in",
"value": "tech,science,education"
}
]
}
}The value must NOT be within the provided comma-delimited list of values.
{
"where": {
"and": [
{
"field": "status",
"operator": "not_in",
"value": ["deleted", "archived", "spam"]
}
]
}
}The value must contain all values provided in the comma-delimited list. Useful for tags or multi-value fields.
{
"where": {
"and": [
{
"field": "tags",
"operator": "all",
"value": "javascript,typescript,react"
}
]
}
}This will only match documents that have ALL three tags.
Only return documents where the value either exists (true) or does not exist (false).
Field exists:
{
"where": {
"and": [
{
"field": "thumbnail",
"operator": "exists",
"value": true
}
]
}
}Field does not exist:
{
"where": {
"and": [
{
"field": "thumbnail",
"operator": "exists",
"value": false
}
]
}
}Note: These spatial/geospatial operators are not currently supported in the SQLite/D1 implementation. For spatial queries, consider:
- Using a spatial database extension
- Implementing application-level filtering
- Using a dedicated geospatial service
Filters support both AND and OR logic, which can be combined for complex queries.
All conditions must be true.
{
"where": {
"and": [
{
"field": "status",
"operator": "equals",
"value": "published"
},
{
"field": "views",
"operator": "greater_than",
"value": 100
},
{
"field": "category",
"operator": "equals",
"value": "tech"
}
]
}
}At least one condition must be true.
{
"where": {
"or": [
{
"field": "status",
"operator": "equals",
"value": "published"
},
{
"field": "status",
"operator": "equals",
"value": "review"
}
]
}
}{
"where": {
"and": [
{
"field": "category",
"operator": "equals",
"value": "tech"
},
{
"field": "views",
"operator": "greater_than",
"value": 50
}
],
"or": [
{
"field": "featured",
"operator": "equals",
"value": true
},
{
"field": "promoted",
"operator": "equals",
"value": true
}
]
}
}This translates to: (category = 'tech' AND views > 50) AND (featured = true OR promoted = true)
Sort results by one or more fields.
{
"sort": [
{
"field": "created_at",
"order": "desc"
}
]
}URL:
GET /api/content?sort=[{"field":"created_at","order":"desc"}]{
"sort": [
{
"field": "priority",
"order": "desc"
},
{
"field": "created_at",
"order": "asc"
}
]
}Control the number of results and pagination.
GET /api/content?limit=25Maximum limit: 1000 results
GET /api/content?limit=25&offset=50This returns results 51-75.
GET /api/content?where={"and":[{"field":"status","operator":"equals","value":"published"}]}&limit=10&offset=20Query nested fields within JSON data using dot notation.
{
"where": {
"and": [
{
"field": "data.author",
"operator": "equals",
"value": "John Doe"
}
]
}
}{
"where": {
"and": [
{
"field": "data.meta.seoTitle",
"operator": "contains",
"value": "Tutorial"
}
]
}
}Get all published tech blog posts with more than 100 views, sorted by views:
curl -X GET "https://your-api.com/api/content?where=%7B%22and%22%3A%5B%7B%22field%22%3A%22status%22%2C%22operator%22%3A%22equals%22%2C%22value%22%3A%22published%22%7D%2C%7B%22field%22%3A%22category%22%2C%22operator%22%3A%22equals%22%2C%22value%22%3A%22tech%22%7D%2C%7B%22field%22%3A%22views%22%2C%22operator%22%3A%22greater_than%22%2C%22value%22%3A100%7D%5D%7D&sort=%5B%7B%22field%22%3A%22views%22%2C%22order%22%3A%22desc%22%7D%5D&limit=10"Decoded filter:
{
"where": {
"and": [
{
"field": "status",
"operator": "equals",
"value": "published"
},
{
"field": "category",
"operator": "equals",
"value": "tech"
},
{
"field": "views",
"operator": "greater_than",
"value": 100
}
]
},
"sort": [
{
"field": "views",
"order": "desc"
}
],
"limit": 10
}Find products in specific categories, within a price range, with available stock:
{
"where": {
"and": [
{
"field": "category",
"operator": "in",
"value": "electronics,computers,gaming"
},
{
"field": "price",
"operator": "greater_than_equal",
"value": 50
},
{
"field": "price",
"operator": "less_than_equal",
"value": 500
},
{
"field": "stock",
"operator": "greater_than",
"value": 0
}
]
},
"sort": [
{
"field": "price",
"order": "asc"
}
],
"limit": 50
}Get recently created or updated content:
{
"where": {
"or": [
{
"field": "created_at",
"operator": "greater_than",
"value": 1704067200000
},
{
"field": "updated_at",
"operator": "greater_than",
"value": 1704067200000
}
]
},
"sort": [
{
"field": "updated_at",
"order": "desc"
}
],
"limit": 20
}Find content with specific tags:
{
"where": {
"and": [
{
"field": "status",
"operator": "equals",
"value": "published"
},
{
"field": "tags",
"operator": "all",
"value": "javascript,tutorial,beginner"
}
]
},
"sort": [
{
"field": "created_at",
"order": "desc"
}
]
}Multi-criteria search with fallback:
{
"where": {
"and": [
{
"field": "status",
"operator": "in",
"value": ["published", "review"]
}
],
"or": [
{
"field": "title",
"operator": "like",
"value": "javascript react tutorial"
},
{
"field": "description",
"operator": "contains",
"value": "react"
},
{
"field": "tags",
"operator": "contains",
"value": "react"
}
]
},
"sort": [
{
"field": "views",
"order": "desc"
},
{
"field": "created_at",
"order": "desc"
}
],
"limit": 25
}The API returns filtered results with metadata:
{
"data": [
{
"id": "abc123",
"title": "Getting Started with React",
"slug": "getting-started-react",
"status": "published",
"collectionId": "blog",
"data": {},
"created_at": 1704067200000,
"updated_at": 1704153600000
}
],
"meta": {
"count": 1,
"timestamp": "2025-01-08T00:00:00.000Z",
"filter": {
"where": {},
"limit": 50
},
"query": {
"sql": "SELECT * FROM content WHERE status = ? LIMIT ?",
"params": ["published", 50]
},
"cache": {
"hit": false,
"source": "database"
},
"timing": {
"total": 45,
"execution": 12,
"unit": "ms"
}
}
}- Use specific filters: The more specific your filters, the faster the query
- Limit results: Always use
limitto prevent large result sets - Index fields: Ensure frequently filtered fields are indexed in the database
- Cache results: The API automatically caches results, but you can also cache on your end
- Combine operators wisely: Use AND for narrowing results, OR for broadening
- Test queries: Use the API console to test complex queries before implementing
If a filter contains errors, the API will return a 400 error:
{
"error": "Invalid filter parameters",
"details": [
"'near' operator not supported in SQLite. Use spatial extension or application-level filtering."
]
}- Use indexed fields: Filter on fields that have database indexes
- Avoid LIKE on large text fields: Use full-text search instead
- Limit result sets: Always specify a reasonable limit
- Use pagination: Don't fetch all results at once
- Cache when possible: Repeated queries with the same filters are cached automatically