Complex Filters
ComplexFilterInput is the primary filtering mechanism in the HappyColis search system. It enables full boolean logic over filter conditions using must (AND), mustNot (NOT), and should (OR) operators, and supports arbitrary nesting for advanced query composition.
Type Definition
graphql
input ComplexFilterInput {
must: [FilterConditionInput] # AND — all conditions must match
mustNot: [FilterConditionInput] # NOT — no condition may match
should: [FilterConditionInput] # OR — at least N must match
minimumShouldMatch: Int # Minimum should matches (default: 1)
}
input FilterConditionInput {
# Exactly one of these fields must be set:
property: String # Facet or numeric field name (for inline conditions)
operator: String # Operator for the condition
values: [String] # Values for facet conditions
value: Float # Value for numeric conditions
nested: NestedFilterCondition # For filtering nested document fields
}See Facet Filters, Numeric Filters, and Nested Filters for details on each condition type.
Operators
| Clause | Elasticsearch Equivalent | Behavior |
|---|---|---|
must | bool.must | All listed conditions must match (AND) |
mustNot | bool.must_not | None of the listed conditions may match (NOT) |
should | bool.should | At least minimumShouldMatch conditions must match (OR) |
minimumShouldMatch | minimum_should_match | Minimum number of should clauses to satisfy (default: 1) |
All three clauses can be combined in a single ComplexFilterInput.
Examples
Filter by state AND currency
Both conditions must match:
graphql
complexFilters: {
must: [
{ property: "state", operator: in, values: ["OPENED"] },
{ property: "currency", operator: in, values: ["EUR"] }
]
}Filter by state OR type
At least one condition must match:
graphql
complexFilters: {
should: [
{ property: "type", operator: in, values: ["B2C"] },
{ property: "type", operator: in, values: ["B2B"] }
],
minimumShouldMatch: 1
}Combined boolean logic
Orders that are OPENED and not LOW priority:
graphql
complexFilters: {
must: [
{ property: "state", operator: in, values: ["OPENED"] }
],
mustNot: [
{ property: "priority", operator: in, values: ["LOW"] }
]
}All three clauses together
Orders belonging to an org, that are NOT cancelled, and are either HIGH or URGENT priority:
graphql
complexFilters: {
must: [
{ property: "organizationId", operator: in, values: ["org-abc123"] }
],
mustNot: [
{ property: "state", operator: in, values: ["CANCELLED"] }
],
should: [
{ property: "priority", operator: in, values: ["HIGH"] },
{ property: "priority", operator: in, values: ["URGENT"] }
],
minimumShouldMatch: 1
}Full Example — Search Orders with Complex Filters
bash
curl -X POST https://api-v3.happycolis.com/graphql \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "query SearchOrders($input: SearchInput!) { orderRecords(input: $input) { hits { objectID invoiceNumber state priority } nbHits nbPages } }",
"variables": {
"input": {
"complexFilters": {
"must": [
{ "property": "organizationId", "operator": "in", "values": ["org-abc123"] }
],
"mustNot": [
{ "property": "state", "operator": "in", "values": ["CANCELLED"] }
],
"should": [
{ "property": "priority", "operator": "in", "values": ["HIGH"] },
{ "property": "priority", "operator": "in", "values": ["URGENT"] }
],
"minimumShouldMatch": 1
},
"sort": [{ "property": "issuedAt", "order": "desc" }],
"hitsPerPage": 25,
"page": 0
}
}
}'javascript
const response = await fetch('https://api-v3.happycolis.com/graphql', {
method: 'POST',
headers: {
'Authorization': `Bearer ${ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: `query SearchOrders($input: SearchInput!) {
orderRecords(input: $input) {
hits { objectID invoiceNumber state priority }
nbHits
nbPages
}
}`,
variables: {
input: {
complexFilters: {
must: [
{ property: 'organizationId', operator: 'in', values: ['org-abc123'] },
],
mustNot: [
{ property: 'state', operator: 'in', values: ['CANCELLED'] },
],
should: [
{ property: 'priority', operator: 'in', values: ['HIGH'] },
{ property: 'priority', operator: 'in', values: ['URGENT'] },
],
minimumShouldMatch: 1,
},
sort: [{ property: 'issuedAt', order: 'desc' }],
hitsPerPage: 25,
page: 0,
},
},
}),
});
const { data } = await response.json();python
import requests
response = requests.post(
'https://api-v3.happycolis.com/graphql',
headers={
'Authorization': f'Bearer {ACCESS_TOKEN}',
'Content-Type': 'application/json',
},
json={
'query': '''
query SearchOrders($input: SearchInput!) {
orderRecords(input: $input) {
hits { objectID invoiceNumber state priority }
nbHits
nbPages
}
}
''',
'variables': {
'input': {
'complexFilters': {
'must': [
{'property': 'organizationId', 'operator': 'in', 'values': ['org-abc123']},
],
'mustNot': [
{'property': 'state', 'operator': 'in', 'values': ['CANCELLED']},
],
'should': [
{'property': 'priority', 'operator': 'in', 'values': ['HIGH']},
{'property': 'priority', 'operator': 'in', 'values': ['URGENT']},
],
'minimumShouldMatch': 1,
},
'sort': [{'property': 'issuedAt', 'order': 'desc'}],
'hitsPerPage': 25,
'page': 0,
}
},
}
)
data = response.json()php
<?php
$client = new \GuzzleHttp\Client();
$response = $client->post('https://api-v3.happycolis.com/graphql', [
'headers' => [
'Authorization' => 'Bearer ' . $ACCESS_TOKEN,
'Content-Type' => 'application/json',
],
'json' => [
'query' => 'query SearchOrders($input: SearchInput!) {
orderRecords(input: $input) {
hits { objectID invoiceNumber state priority }
nbHits
nbPages
}
}',
'variables' => [
'input' => [
'complexFilters' => [
'must' => [
['property' => 'organizationId', 'operator' => 'in', 'values' => ['org-abc123']],
],
'mustNot' => [
['property' => 'state', 'operator' => 'in', 'values' => ['CANCELLED']],
],
'should' => [
['property' => 'priority', 'operator' => 'in', 'values' => ['HIGH']],
['property' => 'priority', 'operator' => 'in', 'values' => ['URGENT']],
],
'minimumShouldMatch' => 1,
],
'sort' => [['property' => 'issuedAt', 'order' => 'desc']],
'hitsPerPage' => 25,
'page' => 0,
],
],
],
]);
$data = json_decode($response->getBody(), true);go
package main
import (
"bytes"
"encoding/json"
"net/http"
)
payload, _ := json.Marshal(map[string]interface{}{
"query": `query SearchOrders($input: SearchInput!) {
orderRecords(input: $input) {
hits { objectID invoiceNumber state priority }
nbHits
nbPages
}
}`,
"variables": map[string]interface{}{
"input": map[string]interface{}{
"complexFilters": map[string]interface{}{
"must": []map[string]interface{}{
{"property": "organizationId", "operator": "in", "values": []string{"org-abc123"}},
},
"mustNot": []map[string]interface{}{
{"property": "state", "operator": "in", "values": []string{"CANCELLED"}},
},
"should": []map[string]interface{}{
{"property": "priority", "operator": "in", "values": []string{"HIGH"}},
{"property": "priority", "operator": "in", "values": []string{"URGENT"}},
},
"minimumShouldMatch": 1,
},
"sort": []map[string]interface{}{
{"property": "issuedAt", "order": "desc"},
},
"hitsPerPage": 25,
"page": 0,
},
},
})
req, _ := http.NewRequest("POST", "https://api-v3.happycolis.com/graphql", bytes.NewBuffer(payload))
req.Header.Set("Authorization", "Bearer "+ACCESS_TOKEN)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)Related
- Facet Filters — Filter on categorical/keyword fields (
in,not_in) - Numeric Filters — Filter on numeric and date fields (
gt,lt,eq, etc.) - Nested Filters — Filter on nested document fields (order lines, delivery contacts, etc.)