Discount Predicates

Some resources in the commercetools API have a predicate or cartPredicate field. In particular, Product Discounts, Cart Discounts, and Shipping Method have predicate fields. This field expects a conditional statement known as a predicate. When a predicate evaluates as true, the API applies the discount or selects a shipping method.

Predicates consist of field identifiers and operators. For more information on creating predicates, see Discount Predicate Identifiers.

You cannot use the syntax described here to construct API queries using the where field. General-purpose queries use a different syntax. For more information, see Query Predicates.

Predicate syntax

Predicates consist of three elements:

  • Predicate Field Identifiers, which target specific fields and characteristics of Carts and Products.
  • Operators, which create logical comparisons between values.
  • Values, which are data – either simple values like 1, "Hello", or true or collections of values like ("xl", "xxl") – to compare with a predicate field identifier.

For example, take the following predicate:

sku = 'AB-123';
  • The predicate field identifier is sku.
  • The operator is =.
  • The value is "AB-123".

Operators always evaluate contextually aware values before comparing or evaluating the predicate. The API ensures that the values of the field identifiers are compatible with the values provided. For example, Strings will only evaluate against Strings. Constructing a predicate that compares different data types – String and Number, for example – returns a 400 Bad Request. One exception to this rule is comparison operators, however.

Operators

Equality operators

Equality operators compare a field identifier with a value.

OperatorDescription
=Checks if the field identifier's value equals the comparison value.
!=, <>Checks if the field identifier's value is not equal to the comparison value.

Example:

product.key = 'holidayTShirt';
  • The predicate field identifier is product.key.
  • The operator is =.
  • The value is "holidayTShirt".

Example:

custom.season = ('spring2019', 'summer2019');
  • The field identifier is custom.season.
  • The operator is =.
  • The values to compare are "spring2019" and "summer2019".

When using the = when comparing collections, = only returns true for exact matches: both "spring2019" and "summer2019" must be present in custom.season, and no other values. In most cases, we recommend using a containment operator to compare collections.

Comparison operators

Comparison operators compare the value of two numbers or number-like fields. You can only use comparison operators for fields that have the following data types:

  • Number
  • Money
  • DateTime
  • Date
  • Time

You can also use comparison operators on the following predicate identifiers:

  • Any Cart Predicate Function.
  • Any Attribute or CustomField with a numerical value of Number, DateTime, Date, or Time.
  • CustomType IDs and Keys (Predicate identifiers: custom.type.id, custom.type.key).
  • SKU (Predicate identifier: sku).
  • Slugs (Predicate identifier: slug).

You can only use comparison operators when comparing a single value to a single value.

OperatorDescription
>Checks if the field identifier's value is numerically greater than the comparison value.
>=Checks if the field identifier's value is numerically greater than or equal to the comparison value.
<Checks if the field identifier's value is numerically less than the comparison value.
<=Checks if the field identifier's value is numerically less than or equal to the comparison value.

Containment operators

Containment operators check if a collection contains a single value. You can only use containment operators on field identifiers with an Array or Set data type:

OperatorDescription
contains, contains anyChecks if a collection contains at least one of the specified values.
contains allChecks if a collection contains all values listed.
inChecks if a field identifier's value is contained in a collection.

Example:

attributes.season contains any ("spring2019", "summer2019")
  • The field identifier is attributes.season.
  • The operator is contains any.
  • The values to check are "spring2019" and "summer2019".

This example evaluates as true if either spring2019 or summer2019 are contained in a product's season attribute. For this request to succeed, season must be a Set.

attributes.season contains all ("spring2019", "summer2019")
  • The field identifier is attributes.season.
  • The operator is contains all.
  • The values to check are "spring2019" and "summer2019".

This example evaluates as true if both spring2019 and summer2019 are contained in a product's season attribute. If only one is present, this example evaluates as false.

Example:

attributes.size in ('xxl', 'xl');
  • The field identifier is attributes.size.
  • The operator is in.
  • The values to compare are "xxl" and "xl".

Defined and empty operators

Defined and empty operators check whether a field or collection has a value. Defined and empty operators are only used on optional fields on a resource.

You can use the is defined and is not defined operators with any single value field.

You can only use the is empty and is not empty fields with collections:

OperatorDescription
is definedChecks if a field identifier exists on a resource and contains a value.
is not definedChecks if a field identifier does not exist on a resource.
is emptyChecks if a collection does not contain values.
is not emptyChecks if a collection contains values. Does not check on the content of the values themselves.

Examples:

channel.id is not defined
  • The field identifier is channel.id.
  • The operator is is not defined.
  • No value is explicitly provided in this predicate, the value, in this case, is implicitly true.

In this example, defining a Product's channel is not required by commercetools when creating a new product. This statement evaluates as true if no product channel is set.

country is defined
  • The field identifier is country.
  • The operator is is defined.
  • No value is explicitly provided in this predicate, the value, in this case, is implicitly true.

In this example, once again, a Cart does not need to have a country defined. This statement evaluates as true if a country is in fact set.

attributes.season is empty
  • The field identifier is attributes.season.
  • The operator is is empty.
  • No value is explicitly provided in this predicate, the value, in this case, is implicitly true.

This example evaluates as true if a Product Type has an season attribute but it does not have a default value.

Combining and nesting operators

You can combine operators to create more complex or nested conditional predicates.

SyntaxDescription
orA logical disjunction: if the first condition or the second condition is true...
andA logical conjunction: if the first condition and the second condition are true...
notA logical negation: if the condition is not true..
( )Nests predicate conditions.

Examples:

custom.bookingStart = "2016-11-24" and custom.bookingEnd = "2016-12-04"
  • The first field identifier is custom.bookingStart.
  • The first operator is =.
  • The first value is "2016-11-24".
  • The and keyword combines the two statements so that both must be true.
  • The second field identifier is custom.bookingEnd.
  • The second operator is =.
  • The second value is "2016-12-04".

You can also nest parentheses:

not(product.key = "holidayTShirt" and(product.price = "10.00 EUR" or product.price = "20.00 EUR"))

This example only evaluates true if the product.key is not "holidayTShirt", and it does not have a price of 10 or 20 euros.

Using the not operator

The not operator, when used in conjunction with any other operator, negates the statement inside of parentheses. This is most useful when using the contains operators, to check if an item is not inside a given collection.

Example:

not(product.key = "holidayTShirt" or product.id = "456")

The or keyword ensures that if only one of the equality statements needs to evaluate as true. If product.id equals 456, or the product.key is "holidayTShirt" outer not statement will evaluate as false.

Discount predicate specification

You can view the discount predicate specification here. The predicate specification is useful when building language parsers.