Discount Predicates

Some resources in the commercetools API have a predicate or cartPredicate field. In particular, Product Discounts, Cart Discounts, and Shippping 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.

Note: 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 which compares different data types – String and Number, for example – returns a 400 Bad Request. One exception to this rule is comparative operators, however.

Operators

Equality operators

Equality operators compare a field identifier with a value.

Operator Description
= Checks if the field identifier’s value equals the comparison value.
in Checks if a field identifier’s value is contained in a collection.
!=, <> 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:

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

Example:

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

Note: 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 Contains operator to compare collections.

Comparative operators

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

  • Number
  • Money
  • DateTime
  • Date
  • Time

You can also use comparative 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 comparative operators when comparing a single value to a single value.

Operator Description
> 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.

Contains operators

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

Operator Description
contains, contains any Checks if a collection contains at least one of the specified values.
contains all Checks if a collection contains all values listed.

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.

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:

Operator Description
is defined Checks if a field identifier exists on a resource and contains a value.
is not defined Checks if a field identifier does not exist on a resource.
is empty Checks if a collection does not contain values.
is not empty Checks 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.
  • There is no explicitly provided value in this predicate, so 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.
  • There is no explicitly provided value in this predicate, so 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.
  • There is no explicitly provided value in this predicate, so 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.

Syntax Description
or A logical disjunction: if the first condition OR the second condition is true…
and A logical conjunction: if the first condition AND the second condition are true…
not A 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. So if product.id equals 456, or the product.key is "holidayTShirt" outer not statement will evaluate as false.