Horizontal Filtering
Filtering the number of returned documents
Introduction
It is a good practice to ensure that only the absolutely required documents are being requested. This can be achieved by providing an expression with the filter query parameter. The expression syntax is similar to what OData uses.
Using properties in expressions
Simple properties
For basic fields, reference them directly by name:
customerName eq 'Coffee & Cream Pottery'
maxCreditDays gt 30
isActive eq trueIn the Enterprise Documents context, we can have:
| Type | Example |
|---|---|
| Simple properties | { "customerName": "Marceli Gierszon", "customerId": "090909" } |
| Nested objects | { "invoice": { "currencyCode": "EUR", "hasFixedCurrency": true } } |
| Array of objects | { "contactPoints": [{ "contactPointType": "1", "address": { "countryCode": "NL" } }] } |
When referencing these properties in a filter expression, use:
- Access nested properties with the path separator
/:
invoice/currencyCode eq 'EUR'- Filter arrays with lambda operators:
contactPoints/any(c: c/address/countryCode eq 'NL')Operators and functions
Below is a quick reference for commonly used operators and functions in filter expressions:
| Category | Operator/Function | Description | Example |
|---|---|---|---|
| Comparison | eq | Equal to | customerName eq 'Marceli Gierszon' |
ne | Not equal to | countryCode ne 'GB' | |
gt | Greater than | invoice/maxCreditDays gt 30 | |
ge | Greater or equal to | invoice/maxCreditDays ge 30 | |
lt | Less than | invoice/maxCreditDays lt 30 | |
le | Less than or equal to | invoice/creditLimit le 100000.0 | |
| Logical | and | Logical AND | countryCode eq 'GB' and customerGroupId eq '1' |
or | Logical OR | countryCode eq 'GB' or customerGroupId eq '1' | |
not | Logical NOT | not (countryCode eq 'GB') | |
| String | contains(field, value) | Contains substring | contains(customerName, 'Giers') |
startswith(field, value) | Starts with substring | startswith(customerName, 'Marceli') | |
endswith(field, value) | Ends with substring | endswith(customerName, 'Gierszon') | |
length(field) | String length | length(customerName) gt 5 | |
indexof(field, value) | Index of substring | indexof(customerName, 'celi') eq 4 | |
substring(field, s, l) | Extract substring | substring(customerName, 1, 3) eq 'ohn' | |
trim(field) | Remove whitespace | trim(customerName) eq 'Marceli Gierszon' | |
| Date/Time | year(field) | Extract year | year(lastUpdated/updatedAt) eq 2025 |
month(field) | Extract month | month(lastUpdated/updatedAt) eq 8 | |
day(field) | Extract day | day(lastUpdated/updatedAt) eq 2 | |
hour(field) | Extract hour | hour(lastUpdated/updatedAt) ge 11 | |
minute(field) | Extract minute | minute(lastUpdated/updatedAt) lt 24 | |
second(field) | Extract second | second(lastUpdated/updatedAt) gt 0 | |
date(field) | Date part | date(lastUpdated/updatedAt) eq 2025-08-07 | |
time(field) | Time part | time(lastUpdated/updatedAt) gt 14:30:00 | |
| Math | round(field) | Round number | round(price) eq 100 |
floor(field) | Round down | floor(average) eq 85 | |
ceiling(field) | Round up | ceiling(score) le 100 | |
| Collection | any(var: cond) | At least one element matches | contactPoints/any(c: c/address/countryCode eq 'NL') |
all(var: cond) | All elements match | contactPoints/all(c: c/address/countryCode eq 'NL') | |
| Special | in1 | Matches one of the items | countryCode in ('GB', 'NL') |
in function is 100. It must have at least one item, and only constant values are accepted.Combining Multiple Conditions Using Parentheses
(countryCode eq 'GB' or countryCode eq 'NL') and customerGroupId eq 'X1'Complex Array Filtering
The example below requests Customers which have a related value with attributeId A21 and value 10.
curl -v "https://unit4-api-address/v1/objects/customers\
?companyId=EN\
&select=companyId,customerId,aliasName,relatedValues(relationName,relatedValue(*))\
&filter=relatedValues/any(e:e/relatedValue/attributeId eq 'A21' and e/relatedValue/dimValue eq '10')\
&orderBy=aliasName desc" \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-H "Accept-Encoding: gzip" \
-H "Accept: application/schema+json"Error messages
In case of an error in the filter expression, an HTTP 400 response code is returned in the format:
{
"code": 2147483647,
"message": "string"
}Commonly encountered errors
Wrong property reference in the expression
{
"code": 1020,
"message": "Could not find a property named 'crreditLimit' on type 'U4ERP.Objects.Customer.Invoice'."
}Filter function incorrectly used due to non-matching argument types
{
"code": 1020,
"message": "No function signature for the function with name 'length' matches the specified arguments. The function signatures considered are: length(Edm.String Nullable=true)."
}On arrays, we can only use the any or all operators
There will be an attempt to cast the array to an entity, but that will fail.
contactPoint.address/countryCode eq 'NL'
{
"code": 1020,
"message": "The child type 'contactPoint.address' in a cast was not an entity type. Casts can only be performed on entity types."
}Tips for Writing Effective Filters
- Use parentheses for complex logic:
(A and B) or (C and D) - Quote string values: Use single quotes for string literals
- Date formats: Use ISO 8601 format for dates:
2024-12-25T14:30:00Z - Property validation: Always check the metadata to confirm available properties and their types