Search query language
Search-backed GraphQL connections accept a query string that Thor translates into Elasticsearch filters. It is a compact search language, not GraphQL syntax and not SQL.
The shared language is used by Admin connections such as products, product variants, orders, customers, and customer groups, and by Storefront products and product variants.
Other fields can also expose an argument named query but implement resource-specific matching. Use the operation’s API reference to confirm that the argument exists; do not assume every query argument supports every field on this page.
Syntax at a glance
| Syntax | Meaning |
|---|---|
portable lamp | Both unfielded terms must match across the resource’s default search fields. |
status:active | Exact, case-insensitive match on a field’s keyword value. |
name:"Portable Lamp" | Phrase match on the named field. |
name:port* | Wildcard prefix match on the named field. |
tag:portable OR tag:lighting | At least one alternative must match. |
NOT status:draft or -status:draft | Exclude a match. |
+tag:featured | Explicitly require a match. |
(vendor:acme OR vendor:thor) status:active | Group alternatives before combining them with another condition. |
Write boolean operators as uppercase AND, OR, and NOT. Whitespace between clauses behaves like AND. Use parentheses whenever an expression mixes OR with required or excluded clauses; this makes intent clear and avoids relying on parser precedence.
Text matching details
- Unfielded terms use prefix-friendly matching across the index’s default fields. Every term must match, but not necessarily in the same field.
- Quoting an unfielded phrase keeps its words together for parsing, but Thor still searches its words as required prefix-capable terms. Use a fielded phrase when word order matters.
- Unquoted
field:valueis an exact keyword match. Add*when you intentionally want prefix matching. - Fielded exact matches are case-insensitive. Dynamic metadata and metafield values match their stored indexed value, so preserve their case.
- Both single and double quotes are accepted for simple phrases. Prefer double quotes; single-quote normalization does not support escaped or nested quotes.
Searchable fields
Field names use the index’s snake_case names, not the GraphQL field’s camelCase spelling. The most useful fields are:
| Resource | Search fields |
|---|---|
| Products | id, name, vendor, status, sku, variant_id, tag, category_id, collection_id |
| Product variants | id, product_id, product_name, product_vendor, product_status, name, sku, barcode, status, tag, category_id, collection_id |
| Orders | id, order_number, external_reference, created_at, customer_id, customer_email, store_id, order_state, payment_state, shipment_state, currency_code |
| Customers | id, first_name, last_name, email, created_at, orders_count |
| Customer groups | id, name, description |
This list documents the fields deliberately placed in each search document. It does not imply that every field supports every operator. In particular, general numeric ranges are not supported just because a field contains a number.
Dates and numeric ranges
The general range implementation supports the created_at date field. Quote an ISO 8601 date or timestamp and use >, >=, <, or <=.
Numeric ranges are supported for public numeric metafields. Thor does not translate arbitrary expressions such as orders_count:>5 or total_gross:>=10000 into numeric ranges.
Product price filtering is a separate, contextual feature described below.
Metadata and public metafields
Product and product-variant search documents expose metadata and public metafields through dynamic field paths.
| Syntax | Behavior |
|---|---|
metadata.<key>:<value> | Exact metadata value. |
metadata.<key>:prefix* | Metadata value prefix. |
metadata.<key>:* | Key exists. |
metafields.<namespace>.<key>:<value> | Exact public metafield value. |
metafields.<namespace>.<key>:prefix* | Public metafield value prefix. |
metafields.<namespace>.<key>:* | Public metafield exists. |
metafields.<namespace>.<key>:>=10 | Numeric public metafield range. |
Private metafields are not placed in these search documents. Numeric comparison values use a dot as the decimal separator and can be negative.
Contextual product price filtering
Storefront product search additionally recognizes integer price comparisons: price:>, price:>=, price:<, and price:<=. Values are minor currency units, so 5000 means EUR 50.00 when the request currency is EUR.
Price filtering requires priceCurrency. Thor resolves the best eligible price for the request’s price channel, country, customer groups, publication state, preview state, and current time, then compares that price with the requested range. Pass the same context on every page.
Join multiple price clauses and other clauses with explicit AND. The specialized price parser removes those clauses before the remaining search expression is translated.
Escaping and troubleshooting
- Prefer a GraphQL variable for
query. It keeps GraphQL quoting separate from search-language quoting. - In JSON, escape double quotes inside the variable value, for example
"query": "name:\"Portable Lamp\"". - An empty or omitted query does not add a search filter.
- Invalid or unsupported syntax can fall back to a lenient Elasticsearch query-string query. Treat that as recovery behavior, not as a documented extension of the language.
- If a filter returns nothing, first remove field clauses, then re-add them one at a time. Check snake_case spelling, exact versus prefix matching, public metafield visibility, minor units, and Storefront request context.