Skip to content

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

ClauseElasticsearch EquivalentBehavior
mustbool.mustAll listed conditions must match (AND)
mustNotbool.must_notNone of the listed conditions may match (NOT)
shouldbool.shouldAt least minimumShouldMatch conditions must match (OR)
minimumShouldMatchminimum_should_matchMinimum 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)

  • 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.)

HappyColis API Documentation