# Query Predicates Predicates provide a way to define complex expressions for querying resources or specifying conditional triggers for API Extensions. The queryable APIs support ad-hoc filtering of resources through flexible predicates. They do so via the `where` query parameter that accepts a predicate expression to determine whether a specific resource representation should be included in the result. API Extensions support predicates via the `condition` field in the [ExtensionTrigger](/urn?urn=ctp%3Aapi%3Atype%3AExtensionTrigger). The Query Predicates syntax differs from the syntax of other predicate types, such as the [predicates used to define discount targets](/api/projects/predicates.md). The structure of predicates and the names of the fields follow the structure and naming of the fields in the documented response representation of the respective query results. Fields of embedded objects are addressed by using parentheses to descend into the object hierarchy. Example predicate for [Product](/urn?urn=ctp%3Aapi%3Atype%3AProduct) fields `masterData.staged.name.en` and `masterData.staged.slug.en`: ```javascript masterData(staged(name(en="Super Product") and slug(en="super-product"))) ``` The encoding of the predicates is `UTF-8` and the predicate must be **URL-encoded** in HTTP requests: ```javascript masterData%28staged%28name%28en%3D%22Super+Product%22%29+and+slug%28en%3D%22super-product%22%29%29%29 ``` With [cURL](https://curl.haxx.se/), you can encode the query with the `--data-urlencode` parameter. When using that parameter, the default method is POST so the `-G` parameter is needed to set the request method to GET. ```cURL title="Example for encoding the query predicate with cURL" $curl -sH "Authorization: Bearer ACCESS_TOKEN" -G --data-urlencode "masterData(staged(name(en="Super Product") and slug(en="super-product")))" https://api.{region}.commercetools.com/PROJECT_KEY/products ``` API endpoints that support Query Predicates allow passing [input variables](/api/predicates/query.md#input-variables) as separate HTTP query parameters. Learn more about how to use Query Predicates to retrieve data from the APIs with the Java and TypeScript SDKs in our self-paced [API queries and Query Predicates](/learning-developer-essentials/api-queries-query-predicates/overview.md) module. ## Query Predicates compared to other query mechanisms Query Predicates filter resources by evaluating logical expressions against fields stored directly on those resources. They do not provide relevance ranking, full-text search, or lookups based on the fields of referenced resources. For these capabilities, use a Search API, such as [Product Search](/api/projects/product-search.md) or [Order Search](/api/projects/order-search.md). Search APIs use their own query language, must be activated before use, and are eventually consistent. Fields that are only available in a Search API cannot be used in Query Predicates. For example, `lineItems.state.state.name` is a field that can only be used in a filter on [Order Search](/api/projects/order-search.md). It is not valid in the `where` query parameter on the [Query Orders](/api/projects/orders.md#query-orders) method because the name of the State is not persisted in the Order resource itself, only the reference to it. The field identifiers used in [Discount Predicates](/api/projects/predicates.md) (the dotted identifiers in the `predicate` and `cartPredicate` fields, such as `attributes.`) also use a different syntax and are not valid in Query Predicates. ### References in Query Predicates Within a Query Predicate, a [Reference](/urn?urn=ctp%3Aapi%3Atype%3AReference) exposes only its `id` and `typeId` fields. You can filter on these fields, but you cannot filter by fields of the referenced resource, such as its `name`. ```javascript // Valid: filter by the id of a referenced resource customerGroup(id = "5e8a5b5e-8a5b-4e8a-8a5b-5e8a5b5e8a5b") // Not valid: you cannot filter by a field of the referenced resource customerGroup(name = "wholesale") ``` ### Embedded data in Query Predicates Values stored directly on a resource, such as a Cart Line Item's `variant.attributes`, are part of the resource representation and can be queried by descending into the object hierarchy. ### Match elements in arrays A predicate on an array matches a resource if **at least one** element of the array satisfies the predicate. There is no "for all elements" operator in Query Predicates. To match resources where **every** element of an array satisfies a condition, enumerate the complement. ```javascript // Match Carts where EVERY Line Item has quantity of at least 2. // There's no "for all" operator, so match the complement: // at least one Line Item qualifies, AND // no Line Item violates the condition. lineItems(quantity >= 2) and not lineItems(quantity < 2) ``` ## Query Predicates by example ### on standard and Custom Fields ```javascript // Compare a field's value to a given value name = "Peter" // For exact match to "Peter". This does not perform substring match. name != "Peter" age < 42 age > 42 age <= 42 age >= 42 age <> 42 // Combine any two conditional expressions in a logical conjunction / disjunction name = "Peter" and age < 42 name = "Peter" or age < 42 // Negate any other conditional expression not (name = "Peter" and age < 42) // Check whether a field's value is or is not contained in // a specified set of values. age in (42, 43, 44) age not in (42, 43, 44) // to be noted: 'in' is much more efficient than several '=' // prefer: name in ("Peter", "Barbara") // to: name = "Peter" or name = "Barbara" // Check whether an array contains all or any of a set of values tags contains all ("a", "b", "c") tags contains any ("a", "b", "c") // Check whether an array is empty tags is empty // Check whether a field exists & has a non-null value name is defined name is not defined // Descend into nested objects dog(age < 7 and name = "Beethoven") // Descend into nested arrays of objects cities(zip > 10000 and zip < 20000) // Query GeoJSON field within a circle // The two first parameters are the longitude and latitude of the circle's center. // The third parameter is the radius of the circle in meter. // Querying within a circle as part of a logical disjunction ('or') is not supported. Attempting to do so will return an error. // Results within a circle are ordered by geolocation distance from lowest to highest. geoLocation within circle(13.37770, 52.51627, 1000) // To query for resources with Custom Fields // enclose the Custom Field with 'custom(fields(=))' // where is as defined in the FieldDefinition and is compliant to the FieldType of the Custom Field // name: "description", FieldType: CustomFieldStringType custom(fields(description="example description")) ``` ### on Attributes When querying an [Attribute](/urn?urn=ctp%3Aapi%3Atype%3AAttribute), we recommend that you use the performance-optimized [Product Search](/api/projects/product-search.md) API whenever possible. For more information, see [inefficient patterns](/api/predicates/query.md#inefficient-patterns). Query for [ProductProjections](/api/projects/productProjections.md) with Attribute values. The following examples only query additional Product Variants. Product indexing for Products and Product Projection queries is limited. This means that adding a large number of indexes for Attributes can impact the performance of Product and Product Projection queries. As a result, we recommend that you only use a small number of unique query patterns that include [Attributes](/api/projects/products.md#attribute). In addition, we recommend that you instead use the [Product Search](/api/projects/product-search.md) or [Product Projection Search](/api/projects/products-search.md#product-projection-search) API for all storefront applications. When querying an Attribute, you must always include both the `attribute-name` and `attribute-value` details in the Query Predicate. Otherwise, a [400 Bad Request](/api/errors.md#400-bad-request) error will occur. ```javascript // for missing attribute variants(not(attributes(name="attribute-name"))) // for single attribute value of TextType variants(attributes(name="attribute-name" and value="attribute-value")) // for multiple attribute values of TextType with same name variants(attributes(name="attribute-name" and value in ("attribute-value-1", "attribute-value-2"))) // for single attribute value of LTextType variants(attributes(name="attribute-name" and value(en="attribute-value"))) // for multiple attribute values of LTextType with same name variants(attributes(name="attribute-name" and value(en="english-value" or de="german-value"))) // for EnumType or LocalizableEnumType variants(attributes(name="attribute-name" and value(key="enum-key"))) // for MoneyType (currencyCode is required) variants(attributes(name="attribute-name" and value(centAmount=999 and currencyCode="EUR"))) // for MoneyType with centAmount within a specific range (currencyCode is required) variants(attributes(name="attribute-name" and value(centAmount > 999 and centAmount < 1001 and currencyCode="EUR"))) // for NumberType variants(attributes(name="attribute-name" and value=999)) // for NumberType with value within a specific range variants(attributes(name="attribute-name" and value > 999 and value < 1001 )) // for DateType, TimeType, or DateTimeType variants(attributes(name="attribute-name" and value="attribute-value")) // for DateType, TimeType, or DateTimeType with a value within a specific range variants(attributes(name="attribute-name" and value > "value-start" and value < "value-end")) // for ReferenceType variants(attributes(name="attribute-name" and value(typeId="reference-type-id" and id="reference-id"))) ``` To search only the Master Variant, use `masterVariant` instead of `variants`: ```javascript // for single attribute value of TextType masterVariant(attributes(name="attribute-name" and value="attribute-value")) ``` To search in all Product Variants you must include both `masterVariant` and `variants` predicates: ```javascript // for single attribute value of TextType masterVariant(attributes(name="attribute-name" and value="attribute-value")) or variants(attributes(name="attribute-name" and value="attribute-value")) ``` To query for [Products](/api/projects/products.md), you must enclose the examples with `masterData(current({example}))` or `masterData(staged({example}))`. ```javascript // for current data masterData(current(variants(attributes(name="attribute-name" and value=999)))) // for staged data masterData(current(masterVariant(attributes(name="attribute-name" and value="attribute-value")))) ``` To query [Carts](/api/projects/carts.md) or [Orders](/api/projects/orders.md) by the Attributes of a [Line Item](/urn?urn=ctp%3Aapi%3Atype%3ALineItem)'s Product Variant, descend through `lineItems`, `variant`, and `attributes`: ```javascript // filter Orders by a text Attribute of a Line Item's Product Variant lineItems(variant(attributes(name="color" and value="blue"))) // filter Carts by a numeric Attribute of a Line Item's Product Variant within a specific range lineItems(variant(attributes(name="rating" and value > 3))) ``` The following examples show the same predicates used with the `where` query parameter: ```bash # filter Orders by a text Attribute of a Line Item's Product Variant GET /{projectKey}/orders?where=lineItems(variant(attributes(name="color" and value="blue"))) # filter Carts by a numeric Attribute of a Line Item's Product Variant within a specific range GET /{projectKey}/carts?where=lineItems(variant(attributes(name="rating" and value > 3))) ``` The dotted identifier syntax used by [Discount Predicate Field Identifiers](/api/projects/predicates.md) (for example, `attributes.rating > 3`) is **not** valid in a `where` query and returns a [400 Bad Request](/api/errors.md#400-bad-request) error. Use the parenthesis syntax shown above instead. A query endpoint usually restricts predicates to only be allowed on a specified subset of a resource representation's fields. The documentation of the endpoint lists fields that can be used for constructing predicates. If multiple predicates are specified via multiple `where` query parameters, the individual predicates are combined in a logical conjunction, just as if they had been specified in a single `where` query parameter and combined with `and`. Example predicate for querying [Products](/api/projects/products.md): ```bash # decoded predicate masterData(current(slug(en="peter-42") and name(en="Peter"))) # URL-encoded predicate masterData%28current%28slug%28en%3D%22peter-42%22%29%20and%20name%28en%3D%22Peter%22%29%29%29 ``` ### on Shipping Methods The following fields on [Shipping Methods](/api/projects/shippingMethods.md#shippingmethod) can be used in Query Predicates: `active`, `createdAt`, `createdBy`, `custom`, `description`, `id`, `isDefault`, `key`, `lastModifiedAt`, `lastModifiedBy`, `name`, `predicate`, `taxCategory`, `version`, `zoneRates`. ### on Carts The following fields on [Cart](/urn?urn=ctp%3Aapi%3Atype%3ACart) can be used in Query Predicates: `anonymousId`, `billingAddress`, `businessUnit`, `cartState`, `country`, `createdAt`, `createdBy`, `custom`, `customLineItems`, `customerEmail`, `customerGroup`, `customerId`, `deleteDaysAfterLastModification`, `discountCodes`, `id`, `inventoryMode`, `itemShippingAddresses`, `key`, `lastModifiedAt`, `lastModifiedBy`, `lineItems`, `locale`, `origin`, `paymentInfo`, `shipping`, `shippingAddress`, `shippingCustomFields`, `shippingInfo`, `shippingRateInput`, `store`, `taxCalculationMode`, `taxMode`, `priceRoundingMode`, `taxRoundingMode`, `taxedPrice`, `totalPrice`, `version`. The following fields on Cart's [LineItem](/urn?urn=ctp%3Aapi%3Atype%3ALineItem) can be used in Query Predicates: `custom`, `discountedPrice`, `discountedPricePerQuantity`, `distributionChannel`, `id`, `name`, `price`, `productId`, `productKey`, `productType`, `quantity`, `state`, `supplyChannel`, `taxRate`, `variant`. The following fields on Cart's [CustomLineItem](/urn?urn=ctp%3Aapi%3Atype%3ACustomLineItem) can be used in Query Predicates: `custom`, `discountedPrice`, `discountedPricePerQuantity`, `money`, `name`, `quantity`, `slug`, `state`. [TaxedPrice](/urn?urn=ctp%3Aapi%3Atype%3ATaxedPrice) fields that can be used in Query Predicates: `totalNet`, `totalGross`. [TaxedItemPrice](/urn?urn=ctp%3Aapi%3Atype%3ATaxedItemPrice) fields cannot be used in Query Predicates. ### on Cart Discounts The following fields on [CartDiscount](/urn?urn=ctp%3Aapi%3Atype%3ACartDiscount) can be used in Query Predicates: `createdAt`, `createdBy`, `custom`, `description`, `id`, `isActive`, `key`, `lastModifiedAt`, `lastModifiedBy`, `name`, `references`, `requiresDiscountCode`, `sortOrder`, `stackingMode`, `stores`, `target`, `validFrom`, `validUntil`, `value`, `version`. Example predicate for querying [Cart Discounts](/api/projects/cartDiscounts.md): ```javascript // query for Cart Discounts with total price discount as target "target(type="totalPrice")" ``` ### on Business Units The following fields on [BusinessUnit](/urn?urn=ctp%3Aapi%3Atype%3ABusinessUnit) can be used in Query Predicates: `id`, `key`, `name`, `contactEmail`, `status`, `createdAt`, `createdBy`, `lastModifiedAt`, `lastModifiedBy`, `addresses`, `shippingAddressIds`, `billingAddressIds`, `defaultShippingAddressId`, `defaultBillingAddressId`, `stores`, `storeMode`, `inheritedStores`, `associates`, `associateMode`, `inheritedAssociates`, `custom`, `customerGroupAssignments`, `parentUnit`, `topLevelUnit`, `unitType`, `approvalRuleMode`, `version`. ```javascript // query for all Divisions within a Company topLevelUnit(key="my-company-key") and unitType="Division" // query for Business Units where a specific Customer is a direct Associate associates(customer(id="customer-id")) // query for Business Units where a specific Customer is a direct or inherited Associate associates(customer(id="customer-id")) or inheritedAssociates(customer(id="customer-id")) // query for Business Units where a Customer has a specific Associate Role associates(customer(id="customer-id") and associateRoleAssignments(associateRole(key="my-role-key"))) ``` To retrieve the full Customer details for Associates in a Business Unit, use [Reference Expansion](/api/general-concepts.md#reference-expansion) with the `expand` query parameter. To include inherited Associates, expand `inheritedAssociates[*].customer` in addition to `associates[*].customer`. ```bash # Get a Business Unit by key with expanded direct and inherited Associate Customer references GET /{projectKey}/business-units/key={key}?expand=associates[*].customer&expand=inheritedAssociates[*].customer # Get all Business Units where a Customer is a direct or inherited Associate, with expanded Customer references GET /{projectKey}/business-units?where=associates(customer(id="customer-id")) or inheritedAssociates(customer(id="customer-id"))&expand=associates[*].customer&expand=inheritedAssociates[*].customer ``` ### on Customers The following fields on [Customer](/urn?urn=ctp%3Aapi%3Atype%3ACustomer) can be used in Query Predicates: `id`, `createdAt`, `lastModifiedAt`, `customerNumber`, `email`, `lowercaseEmail`, `stores`, `firstName`, `lastName`, `middleName`, `title`, `addresses`, `defaultShippingAddressId`, `defaultBillingAddressId`, `isEmailVerified`, `externalId`, `customerGroup`, `customerGroupAssignments`, `locale`, `salutation`, `key`. Example predicate for querying [Customers](/api/projects/customers.md): ```bash # decoded predicate lowercaseEmail="peter@example.com" # URL-encoded predicate lowercaseEmail%3D%22peter%40example.com%22 ``` ### on Orders The following fields on [Order](/urn?urn=ctp%3Aapi%3Atype%3AOrder) can be used in Query Predicates: `createdAt`, `lastModifiedAt`, `completedAt`, `orderNumber`, `customerId`, `customerEmail`, `anonymousId`, `country`, `totalPrice`, `taxedPrice`, `shippingAddress`, `billingAddress`, `customerGroup`, `orderState`, `shipmentState`, `paymentState`, `syncInfo`, `returnInfo`, `lineItems`, `customLineItems`, `cart`, `paymentInfo`, `state`, `locale`, `inventoryMode`, `shippingRateInput`, `shippingInfo`. The following fields on Order's [LineItem](/urn?urn=ctp%3Aapi%3Atype%3ALineItem) can be used in Query Predicates: `custom`, `discountedPrice`, `discountedPricePerQuantity`, `distributionChannel`, `id`, `name`, `price`, `productId`, `productKey`, `productType`, `quantity`, `state`, `supplyChannel`, `taxRate`, `variant`. The following fields on Order's [CustomLineItem](/urn?urn=ctp%3Aapi%3Atype%3ACustomLineItem) can be used in Query Predicates: `custom`, `discountedPrice`, `discountedPricePerQuantity`, `money`, `name`, `quantity`, `slug`, `state`. ```javascript // query for Orders that are awaiting stock shipmentState="Backorder" // query for Orders created in August 2022 createdAt > "2022-08-01T00:00:00.000Z" and createdAt < "2022-09-01T00:00:00.000Z" ``` ### on Shopping Lists The following fields on [ShoppingList](/urn?urn=ctp%3Aapi%3Atype%3AShoppingList) can be used in Query Predicates: `key`, `name`, `customer`, `slug`, `description`, `lineItems`, `textLineItems`, `deleteDaysAfterLastModification`, `anonymousId`, `store`, `custom`. The following fields on ShoppingList's [TextLineItem](/urn?urn=ctp%3Aapi%3Atype%3ATextLineItem) can be used in Query Predicates: `id`, `key`, `name`, `quantity`, `addedAt`, `description`, `custom`. ```json // query Shopping Lists of Customer with ID "657337d1-b0f3-4582-a1c1-c096c165f029" customer(id = "657337d1-b0f3-4582-a1c1-c096c165f029") // query Shopping Lists that have a TextLineItem with key "recommended-123" textLineItems(key = "recommended-123") ``` ### on Custom Objects The field `value` on [Custom Objects](/api/projects/custom-objects.md#customobject) can be used as a predicate but is not checked for validity. `value` can contain any number, string, boolean, array, object, or [common API data type](/api/types.md). The following examples are based on having a Custom Object with the following values: ```json { "container": "example-container", "key": "example-key", "value": { "exampleText": "This is example text", "exampleNumber": 1234, "exampleObject": { "exampleBoolean": true, "exampleArray": ["first", "second", "third"] } } } ``` ```js // Query Custom Objects for a field within value value(exampleNumber > 1233) // Query Custom Objects for a field within an object value(exampleObject(exampleBoolean = true)) // Query Custom Objects for an array within an object value(exampleObject(exampleArray is not empty)) ``` ## Input variables Query predicates support the use of input variables to simplify working with query strings that contain dynamic values. Using input variables also eases log analysis because identical query use cases have identical `where` query parameter values. Because the request URL and headers together must not exceed **about 15 kilobytes**, input variables are also the recommended way to keep long predicates, such as an `in (...)` expression with many values, within the allowed size. See [URL and headers size](/api/limits.md#url-and-headers-size). Split very large value sets across multiple requests. Inside the Query Predicate string, references to input variables must be prefixed with a colon `:`. All input variables referenced in the Query Predicate must be added to the URI as separate HTTP query parameters whose names must be prefixed with `var.`. The same input parameter can be passed multiple times to be used as an array of values. The actual names of the input variables must consist of alphanumeric characters only. Note, that input variables on [Custom Fields](/api/projects/custom-fields.md) are only supported for fields of the [CustomFieldStringType](/urn?urn=ctp%3Aapi%3Atype%3ACustomFieldStringType). ## Input variable examples HTTP query using one input variable: ```bash # decoded: ?where=firstName = :name&var.name=Peter # URL-encoded: ?where=firstName%20%3D%20%3Aname&var.name=Peter ``` HTTP query using an array input variable: ```bash # decoded: ?where=masterVariant(sku in :skus) or variants(sku in :skus)&var.skus=sku1&var.skus=sku2&var.skus=sku3 # URL-encoded: ?where=masterVariant%28sku%20in%20%3Askus%29%20or%20variants%28sku%20in%20%3Askus%29&var.skus=sku1&var.skus=sku2&var.skus=sku3 ``` Referencing input variables in Query Predicates: ```javascript // Compare a field's value to a given input variable value name = :name // Check whether a field's value is or is not contained in // a specified set of input variable values. age in :ages age in (:age1, :age2, :age3) age not in :ages age not in (:age1, :age2, :age3) // Check whether an array contains all or any of a set of input variable values tags contains all :tags tags contains all (:tag1, :tag2, :tag3) tags contains any :tags tags contains any (:tag1, :tag2, :tag3) // Referencing an input variable multiple times masterVariant(sku in :skus) or variants(sku in :skus) ``` ## Performance considerations Query predicates are translated to database queries whose efficiency depends on how well the database can use indexes. **Indexes are managed automatically**. Some indexes are present on all projects, others are added dynamically. For example, if you add a Custom Field to your carts and start querying it, the system will add an index to the project to improve performance if it meets criteria like query frequency. The automatic index creation needs to collect a significant amount of data to not optimize for outlier scenarios. That's why it can take up to two weeks before a new index is added. Efficient queries can be fast on extremely large datasets and inefficient queries can be fast on small datasets, too. But inefficient query patterns on large datasets cause long-running and resource-intensive queries. Such queries can affect the overall performance of a Project. ### Inefficient patterns Not all Query Predicates can be easily supported with an index, so if possible **avoid the following patterns on large datasets**: - **Query Predicates on Attributes** of [Products](/urn?urn=ctp%3Aapi%3Aendpoint%3A%2F%7BprojectKey%7D%2Fproducts%3AGET) and [Product Projections](/urn?urn=ctp%3Aapi%3Aendpoint%3A%2F%7BprojectKey%7D%2Fproduct-projections%3AGET): Because [Attributes](/api/projects/products.md#attribute) aren't indexed by default, the initial performance of queries for Projects with a large number of Product Variants might be inefficient. **Use [Product Search](/api/projects/product-search.md) or [Product Projection Search](/api/projects/product-projection-search.md) instead.** To increase the performance of queries, you can let the platform create an index on your Attributes. Before introducing a new pattern to a project, you must perform a few hundred consecutive API requests to trigger the automatic indexing feature. If responses remain slower than two seconds on the next day after your test run, then contact [support@commercetools.com](https://support.commercetools.com/). - **Fields nested inside arrays**: The query becomes inefficient for predicates on arrays that contain many entries. For example, `variants(attributes(name = "attribute-name" and value = "attribute-value"))`. - Querying for a **condition that is true for the majority** of resources, for example `custom(state = "Done")`. - Negations, such as `state != "Open"` or `state is not defined`. - The `empty` operator on arrays, such as `lineItems is empty` or `lineItems is not empty`. - The `in` operator on arrays: The number of values provided in the predicate should **not exceed 50 entries**, for example: `sku in (value1, value2 .. value50)`. - The `not in` operator excludes the matching resources and returns the remaining resources. This operator is inefficient because it does not use indexes effectively. For example, `sku not in (value1, value2)` excludes any resource for which the `sku` value is either `value1` or `value2` and returns all other resources. ### Efficient patterns The following patterns are supporting efficient query execution: - Non-nested **fields that heavily reduce the subset** of resources to filter, for example `custom(state = "WaitingForExternalApproval")` (assuming there are few resources waiting for external approval) - If possible, prefer equality over other operators. For example, `(state = "Done" or state = "Canceled)"` can be faster than `(state != "Open")` in a query that contains further expressions. - Queries on Orders, Carts, Customers, etc. may be fast in the beginning, but slow down over time as your Project grows. **Include a time range**, for example `lastModifiedAt > $1-week-ago and ...` (replace `$1-week-ago` with an actual date). Try defaulting the time range to the smallest value that is acceptable for the use case. Alternatively, try filtering by a field value that naturally only occurs in recently created resources. ### Sorting and query performance Sorting can also be supported by indexes. For best performance, the same index can be used for filtering and sorting. If possible, re-use a field from the Query Predicate for sorting. For example, if your filter query is `lastModifiedAt > $1-week-ago`, sorting on `lastModifiedAt` is advised since it is more performant than sorting on a different field, like `id`. ### Deactivate calculating the total Deactivating the calculation of the `total` field in the [PagedQueryResult](/api/general-concepts.md#pagedqueryresult) will improve the performance of the query. Whenever the `total` is not needed, deactivate its calculation by using the query parameter `withTotal=false`. ## Use predicates in conditional API Extensions Besides querying resources, the predicates syntax also allows you to define complex expressions for the conditional execution of [API Extensions](/api/projects/api-extensions.md#conditional-triggers). ### Unsupported operators A few minor differences aside, the behavior of the language and the operators used are the same for both querying resources and defining API Extension conditions. The features not supported in conditional API Extensions are: - [Input variables](/api/#input-variables) - The `within-circle` operator ### React to data changes with predicates In addition to the existing set of predicates, conditional API Extensions support the ability to check for changes to a resource's properties. For example, if your Extension is configured to be triggered for update actions to Carts, you can check whether the update action contains changes to the Cart's shipping information. By using the `has changed` operator, you can ensure that the Extension is called only when certain properties are updated in the update action triggering the Extension. Given a valid predicate, the `has changed` operator evaluates to true for all create actions. The negation of `has changed` is also supported. Using `has not changed` ensures that the Extension only triggers when certain properties do not change during the update action. Given a valid predicate, the `has not changed` operator evaluates to false for all create actions. Below are a few examples on how the `has changed` and `has not changed` operators behave during create and update actions: ```javascript // Evaluates to true if the name field is updated during the API call name has changed // Evaluates to true if the name field is not updated during the API call name has not changed // Evaluates to true if the resource is created with the name attribute name has changed // Evaluates to true if the quantities of existing Line Items change, or if new Line Items are added lineItems(quantity has changed) // Evaluates to true if a Line Item is added, removed, or updated lineItems has changed // Evaluates to false if the field shoeSize does not exist shoeSize has changed ``` This feature requires a comparison between the current and previous versions of a resource during an update or create action. Therefore, the `has changed` and `has not changed` operators are only supported when defining API Extension conditions. To learn more about using Query Predicates with API Extensions, see the [Implementing an API Extension](/tutorials/extensions.md) tutorial. ## Related pages - [Area overview page with navigation](/api.md) - [Previous page: Common types](/api/types.md) - [Next page: Search query language](/api/search-query-language.md)