Queries and the SDKs

Learn how to use Query Predicates with the SDK to query your Composable Commerce resources.

  • After completing this page, you should be able to:

    • Identify compound expressions that correctly match their requirements.
    • Identity correct usage of input variables in Query Predicates.
  • On the following page, you will learn about how to use queries in your API requests to make sure that your response from the Composable Commerce API delivers only the results that you need.

    We will learn the concepts in three steps, where we will:

    • Construct simple queries following the basic syntax checking the value of one field on the resource.
    • Combine multiple simple queries using logical operators.
    • Enhance our multiple queries with input variables.

    Let’s get into it!

    Predicate Syntax Basics

    Query Predicates are used in the where query parameter. Each query endpoint lists its possible query parameters. Let's take a look at the following example for Query Customers:

    List of possible query parameters listed in the docs for the Query Customers endpoint.

    As mentioned on the previous page, the basic syntax follows this schema:

    field operator value

    Fields are taken from the resource under inspection, but it’s important to note that not all fields that a resource representation provides can be used in a query. In the docs, the Query Predicates page is a great starting point for learning about which fields can be used in a query. Have a look at the documentation for all possible operators and a long list of examples.

    Use the SDKs to make queries

    Let’s have a look at how we can use Query Predicates with our SDKs. We will take a simple example to start with: let's try to fetch all customers that live in Berlin.

    First, let’s break that statement down: all customers living in Berlin. How can we turn it into a predicate? First, let’s rewrite it in straightforward English; we want to fetch all customers whose Shipping Address has Berlin as its city. Then, in our predicate syntax, this could look something like:

    addresses(city = "Berlin")

    Now let’s see how we can write that with our TypeScript and Java SDKs:

    The query is not limited to a single customer, so we would see a CustomerPagedQueryResponse in the response body. Inside the results fields, we can find the list of all customers that matched the predicate.

    Compound expressions

    Now imagine a scenario where you have to search for customers from Berlin who are not in a particular Customer Group. You could approach creating a query for this scenario in two ways. You could either fetch this data in two calls (Customers from Berlin, and Customers who are not in the Customer Group) and then go through the results to find the intersecting elements. Or, you could use a compound expression to do the job for you.

    Composable Commerce predicate compound expressions have the following syntax:

    predicate logical-operator predicate

    We can use the following logical operators: and, or, and not with our compound expressions.

    It is also possible to combine multiple compound expressions together to make even more complex compound expressions by using parentheses.

    Here are a few examples:

    • To search for a Customer with first name and last name: firstName = "Peter" and lastName = “Porter”
    • Find customers from either Berlin or Munich: addresses(city = "Berlin" or city = "Munich")
    • Find all the customers from Germany except Berlin: addresses(country = "DE" and not(city= "Berlin"))

    Let's look for a moment at examples related to Products. Have a go yourself at translating the following queries into natural English:

    • variants(attributes(name="color" and value="red"))
    • variants(attributes(name="color" and value(en-US="red")))

    Both of these queries would achieve the same result: returning all Products that have Product Variants in red. Take a special note however of the use of the localized attribute in the second example.

    Now let’s see how to create compound expressions with the SDK. Let’s run a request with a compound expression. Pay particular attention to the lines where the predicate is presented.

    The predicate we are using is based on the Composable Commerce sample data that is downloaded with a trial Project. If you are using your own data, then you need to adjust the predicate to match your data set.

    Using the SDK you can easily combine multiple queries together. In the following examples, we will cover how this works in the Java and TypeScript SDK. You will see that there are some slight differences in how each SDK allows you to express predicates with multiple conditions.

    TypeScript

    import { apiRoot } from "../impl/apiClient.js";
    async function productPredicate() {
    try {
    const response = await apiRoot
    .productProjections()
    .get({
    queryArgs: {
    where:
    'variants(attributes(name = "colorlabel" and value(en-GB = "Black")))',
    },
    })
    .execute();
    console.log("Summary", JSON.stringify(response.body, null, 2));
    } catch (error) {
    console.log(JSON.stringify(error, null, 2));
    }
    }
    productPredicate();

    Java

    Using the Java SDK we can chain multiple conditions using .withWhere() and .addWhere(). This combines the predicates with an and operator. This predicate will be converted to this:

    variants(attributes(name = "colorlabel" and value(en-GB = "Black")))

    logger.info(
    "Products available in Red: " +
    projectApiRoot
    .productProjections()
    .get()
    .withWhere("variants(attributes(name = \"color\"))")
    .addWhere("variants(attributes(value(en = \"red\")))")
    .executeBlocking()
    .getBody()
    .getResults()
    .size()
    );

    Input Variables

    Let’s move on to a different use case. Imagine you want to display the number of customers living in the same city as another customer. The solution here would involve creating a query that is based on the current Customer's city, and then you would need to query for the remaining Customers. The city in this example is a dynamic input.

    We can use input variables for dynamic inputs using the following syntax:

    field operator :variable&var.variable = value

    Input variables are useful when you are creating a Query Predicate that uses a dynamic value supplied only at the time of running the query. For example, getting all Products from a Category where the Category will be selected by the user.

    category = :categoryId&var.categoryId = categoryId

    You can even use multiple variables to check multiple values. See the following example:

    variants(sku in :skus)&var.skus=sku1&var.skus=sku2&var.skus=sku3

    This query is intended to retrieve multiple products where any of the variants match one of the SKUs provided in the :skus variable. Let’s break down this predicate to better understand it:

    • variants(sku in :skus): this part of the query is checking for any Product Variants where the sku is in the list of SKUs provided by the :skus variable.
    • &var.skus=sku1&var.skus=sku2&var.skus=sku3: these are the predicate parameter values that define the :skus variable. Each var.skus parameter specifies an SKU value to be included in the search.

    The query will return products that have any of the specified SKUs (sku1, sku2, sku3) in their Product Variants. It uses the logical in operator, which matches any Product Variant that has an SKU within the provided list.

    Let’s apply this to a short example request and use the SDKs. We are interested in getting a count of Customers in the same city as the current Customer. In our example, we want to get a Customer’s ID for a Customer that has a default Shipping Address and update the variable customerId.

    Test your knowledge