Skip to documentation content

Query Syntax

Query Syntax

The advanced query syntax accepted by the query argument on datastore_items and profiles: fields, conditions, grouping, and keyword synonyms.

The datastore_items and profiles methods accept a query argument with its own advanced syntax, a small query language, not Liquid. It applies identically to both: a datastore_items query filters on the item's custom fields, and a profiles query filters on the profile's custom settings/attributes. Neither one can target a built-in/reserved property this way.

A query is one or more phrases, and a phrase is one of:
• a field on its own: matches any item where that field has a value at all
• a field with a condition and a value: [field] [condition] [value]
• a parenthesized group of phrases: ( [phrase] )
• an inverted phrase or group: NOT [phrase]
• two phrases joined by AND or OR

Fields and Values

How a query's field and value tokens are written, including quoting rules.

A field is the custom field's key (its FieldID), written as an unquoted word (letters, numbers, dashes, and underscores only) or as a quoted string. A value is a quoted string, an unquoted word, or, for the numeric comparisons below, a positive or negative integer. Inside a quoted string, double the quote character to include it literally ("He said ""hi""" or 'It''s here'); quoted whitespace is kept as written, unlike whitespace between tokens, which is ignored.

Conditions

The comparison operators a query phrase can use between a field and a value.

Write a phrase as [field] [condition] [value]:
• = or ==: equals
• != or <> or ><: not equals
• <: less than
• <=: less than or equal
• >: greater than
• >=: greater than or equal
• CONTAINS or LIKE: field's text contains the value (exact synonyms, with identical behavior, not two different kinds of match)

AND, OR, and NOT

Joining and inverting phrases with AND, OR, and NOT, their interchangeable spellings, and operator precedence.

Join phrases with AND or OR, or invert one with NOT. Each has several interchangeable spellings:
• AND: and, +, &, or &&
• OR: or, |, or ||
• NOT: not, or !
• a bare - immediately before a phrase (not part of a negative number) also means "and not", so a - b is the same as a and not b

When a query mixes AND and OR without parentheses, AND binds tighter than OR: a and b and c or d and e or f means (a and b and c) or (d and e) or f. Use parentheses to make the grouping explicit rather than relying on this precedence; it keeps the query readable even when the default grouping is what you want.

Case Sensitivity

Query keywords, field IDs, and values all match without regard to case.

Query keywords (and, or, not, contains, like, and the comparison operators) are not case-sensitive: AND, and, and And all work. Field IDs and values are also matched without regard to case, but that's not a reason to write them any way you like: use the field's real, correctly-cased FieldID. That's how the field is referenced everywhere else in a template, and consistent casing keeps a template readable and easy to search.

Using a Query

Building a query string in Liquid and passing it to the query argument, with safe escaping for user input.

Build the query string in Liquid, often with capture for anything beyond a literal string, and pass it to the query argument, escaping any value built from user input by doubling embedded quote characters so it can't break out of its quotes.
Example Build a query string with captureCapture a query string that searches two fields with CONTAINS and OR, then pass it to datastore_items.
Liquid
{%- capture var filterQuery -%}description CONTAINS "{{ term }}" OR requirements CONTAINS "{{ term }}"{%- endcapture -%}
{%- datastore_items items = datastore:entity query:filterQuery -%}
Example Get datastore items using an advanced queryBuild a query string from request params and pass it to datastore_items to filter by custom fields (e.g. beds, baths).
Liquid
{%- var query = "movein_ready = true" -%}
{%- if request.query_params.beds is_int -%}
	{%- set query = query | append: " and beds = " | append: request.query_params.beds -%}
{%- endif -%}
{%- if request.query_params.baths is_int -%}
	{%- set query = query | append: " and baths = " | append: request.query_params.baths -%}
{%- endif -%}
{%- datastore_items collection = datastore:entity query:query -%}
Example Sample datastore item queriesThree query patterns for datastore_items: a simple numeric range/comparison, a complex nested query with NOT and optional conditions, and a dynamically built query across configurable fields.

Simple range and comparison query

Liquid
{%- datastore_items items = datastore:"Hotels" query:"number_of_rooms > 100 AND average_room_price <= 100" -%}

Filters the Hotels datastore to items with more than 100 rooms and an average room price of 100 or less, combining two numeric comparisons with AND.

Complex nested query with NOT and an optional condition

Liquid
{%- capture query -%}
  is_vegan
  OR
  (
	number_of_ingredients < 6
	AND (
	  NOT ingredients contains chicken
	  -ingredients contains pork
	  - ingredients LIKE 'beef'
	  {%- if other_meat_to_avoid is_valid -%}
		AND !(ingredients CONTAINS "{{other_meat_to_avoid | replace: '"', '""' }}")
	  {%- endif -%}
	)
	AND NOT (
	  'contains_dairy'
	  OR ingredients contains egg
	)
  )
{%- endcapture -%}
{%- datastore_items items = datastore:'Recipes' query:query -%}

Matches vegan recipes, or recipes with fewer than 6 ingredients that avoid chicken, pork, and beef (using NOT and the bare - shorthand for AND NOT), plus an optional other_meat_to_avoid the caller may supply, and excludes anything marked contains_dairy or containing egg.

Query multiple configurable fields dynamically

Liquid
{%- set query = "" -%}
{%- set fieldvalue = request.query_params['fieldvalue'] | urldecode -%}
{%- if request.query_params['fieldnames'] is_valid and fieldvalue is_valid -%}
  {%- var fieldnames = request.query_params['fieldnames'] | urldecode | split: ',' -%}
  {%- var queryparts = '' | compact -%}
  {%- for field in fieldnames -%}
	{%- capture querypart %}{{field}} = "{{fieldvalue | replace: '"', '""'}}"{% endcapture -%}
	{%- set queryparts = queryparts | concat: querypart -%}
  {%- endfor -%}
  {%- set query = queryparts | join: ' OR ' -%}
{%- endif -%}
{%- datastore_items items = datastore:entity query:query -%}

Builds an OR query across a caller-supplied, comma-separated list of field names (fieldnames), matching each one against the same escaped value (fieldvalue) from the request's query string.