Filtering, Search & Ordering | Moloni ON API
Moloni ONGuidesAPI ReferenceExplorer
Guides

Filtering, Search & Ordering

All list endpoints in the Moloni ON API accept an options argument that lets you filter, search and order results. These work alongside pagination and can be combined freely. This guide uses the products query as an example, but the pattern is the same across all list endpoints.

The options argument

List queries accept an options input with these fields:

query {
  products(companyId: 1, options: {
    filter: [...]
    search: { ... }
    order: [...]
    pagination: { ... }
  }) {
    errors { field msg }
    data { ... }
    options { ... }
  }
}

All fields are optional; use only what you need.

Filtering

Filters let you narrow results by exact conditions on specific fields. You pass an array of filter objects, each with a field, a comparison operator, and a value.

Structure

filter: [
  { field: <FilterField>, comparison: <Comparison>, value: <String> }
]

For products, the filter input is ProductFilterOptions, with fields defined in ProductFilterField.

Comparison operators

The Comparison enum provides these operators:

OperatorDescriptionExample value
eqEqual to"1"
neNot equal to"0"
gtGreater than"100"
gteGreater than or equal"100"
ltLess than"50"
lteLess than or equal"50"
likeContains (partial match)"CHAIR"
notLikeDoes not contain"DRAFT"
inIn a set of values"[1, 2, 3]"
notInNot in a set of values"[4, 5]"

Examples

Filter visible products only:

query {
  products(companyId: 1, options: {
    filter: [
      { field: visible, comparison: eq, value: "1" }
    ]
  }) {
    data { productId name reference }
  }
}

Filter products with price ≥ 100 in a specific category:

query {
  products(companyId: 1, options: {
    filter: [
      { field: price, comparison: gte, value: "100" }
      { field: productCategoryId, comparison: eq, value: "5" }
    ]
  }) {
    data { productId name price }
  }
}

Multiple filters are combined with AND logic, meaning all conditions must match.

Filter products updated after a specific date:

query {
  products(companyId: 1, options: {
    filter: [
      { field: updatedAt, comparison: gte, value: "2025-01-01" }
    ]
  }) {
    data { productId name }
  }
}

Filter by multiple IDs using in:

query {
  products(companyId: 1, options: {
    filter: [
      { field: type, comparison: in, value: "[1, 2, 3]" }
    ]
  }) {
    data { productId name type }
  }
}

Some filter fields reference related entities using double-underscore notation. For example, to filter products by supplier:

query {
  products(companyId: 1, options: {
    filter: [
      { field: suppliers__supplier__supplierId, comparison: eq, value: "42" }
    ]
  }) {
    data { productId name }
  }
}

Other relational filter fields for products include warehouses__warehouse__warehouseId, taxes__tax__taxId and identifications__text, among others. See ProductFilterField for the full list.

Search performs a partial text match across one or more fields. Unlike filters, search uses a single object (not an array).

Structure

search: { field: <SearchField>, value: <String> }

For products, the search input is ProductSearchOptions, with fields defined in ProductSearchField.

The ALL field

Most endpoints provide a special ALL field that searches across every searchable field at once. This is the most common choice:

query {
  products(companyId: 1, options: {
    search: { field: ALL, value: "widget" }
  }) {
    data { productId name reference }
  }
}

This searches the product name, reference, price, notes, summary, supplier references, and identification codes simultaneously.

Searching a specific field

To search only within a specific field:

query {
  products(companyId: 1, options: {
    search: { field: reference, value: "CHAIR-001" }
  }) {
    data { productId name reference }
  }
}

Ordering

Ordering sorts results by one or more fields. You pass an array of order rules, each with a field and a sort direction.

Structure

order: [
  { field: <OrderField>, sort: <Sort> }
]

The Sort enum has two values: ASC (ascending) and DESC (descending).

For products, the order input is ProductOrderOptions, with fields defined in ProductOrderField.

Single field ordering

query {
  products(companyId: 1, options: {
    order: [{ field: name, sort: ASC }]
  }) {
    data { productId name }
  }
}

Multiple field ordering

When you pass multiple order rules, they are applied in sequence: the first rule is the primary sort, the second breaks ties, and so on:

query {
  products(companyId: 1, options: {
    order: [
      { field: stock, sort: DESC }
      { field: name, sort: ASC }
    ]
  }) {
    data { productId name stock }
  }
}

This returns products with stock first (descending), then alphabetically by name within each group.

Combining everything

All options can be used together. Filters and search narrow the result set, ordering sorts it and pagination slices it:

query {
  products(companyId: 1, options: {
    filter: [
      { field: visible, comparison: eq, value: "1" }
      { field: price, comparison: gte, value: "10" }
    ]
    search: { field: ALL, value: "chair" }
    order: [{ field: price, sort: ASC }]
    pagination: { page: 1, qty: 20 }
  }) {
    errors { field msg }
    data {
      productId
      name
      reference
      price
    }
    options {
      filter { field comparison value }
      search { field value }
      order { field sort }
      pagination { page qty count }
    }
  }
}

Response:

{
  "data": {
    "products": {
      "errors": [],
      "data": [
        { "productId": 88, "name": "Office Chair Basic", "reference": "CHAIR-001", "price": 49.99 },
        { "productId": 102, "name": "Office Chair Pro", "reference": "CHAIR-002", "price": 149.99 }
      ],
      "options": {
        "filter": [
          { "field": "visible", "comparison": "eq", "value": "1" },
          { "field": "price", "comparison": "gte", "value": "10" }
        ],
        "search": { "field": "ALL", "value": "chair" },
        "order": [{ "field": "price", "sort": "ASC" }],
        "pagination": { "page": 1, "qty": 20, "count": 2 }
      }
    }
  }
}

The options object in the response echoes back exactly what was applied, including the pagination.count reflecting the total number of records matching all filters and search, before pagination is applied.

Next steps

  • Pagination: Page through filtered and searched result sets
  • Error Handling: Understand the error model returned by all operations