Variations mapping

Variations mapping is a powerful feature designed to optimize the way product variations are handled and presented in API results. It addresses the challenge of efficiently managing and displaying products that come in multiple variations (for example, color, size, pattern) without overwhelming the user with excessive information or causing performance issues due to large response payloads.

The core value of variations mapping lies in its ability to group product variations by any specified attribute(s) and selectively retrieve only the necessary information for each group. This is particularly useful for displaying product swatches or other variation-specific data on product listing pages, where only a subset of variation data (like color and size) is relevant.

Key benefits of variations mapping include:

  1. Reduced Payload Size: By allowing the retrieval of only the needed variation metadata (for example, image URLs for different colors), variations mapping significantly reduces the size of the data payload. This leads to faster response times and improved performance, enhancing the user experience.
  2. Flexible Data Aggregation: Variations mapping supports various aggregation functions (min, max, first, all, etc.), enabling the customization of how variation data is summarized. For example, one can easily obtain the minimum and maximum prices across all variations of a product, or gather all sizes available for a particular color.
  3. Customizable Grouping: Products can be grouped by any combination of attributes (for example, color and size), allowing for a highly customizable presentation of variation data. This flexibility supports a wide range of use cases, from simple color swatches to more complex variation matrices.
  4. Efficient Data Retrieval: By specifying exactly what variation data to retrieve and how to group it, variations mapping streamlines the data retrieval process. This not only improves backend efficiency but also simplifies the frontend logic needed to display variation information.

Schema overview

The variations_map parameter must be a valid JSON object with the following key components:

  • filter_by: Filtering expression that's used to apply a pre-aggregation filtering on product variations. This filtering is executed before any grouping or aggregation operations are performed on the variations data. The purpose of this clause is to narrow down the set of variations to those that match specific criteria.
  • group_by: Specifies how variations should be grouped.
  • values: Defines which fields to retrieve from each group and how to aggregate them.
  • dtype: Determines the type of the variations_map that will be returned in the response.
{
  "filter_by": {
    "and": [
      {"field": "<field path>", "value": "<value>"},
      {
        "or": [
          {"not": {"field": "<field path>", "value": "<value>"}},
          {"not": {"field": "<field path>", "value": "<value>"}}
        ]
      },
    ]
  },
  "group_by": [
    {"name": "<alias>", "field": "<field path>"}
  ],
  "values": {
    "<alias>": {
        "aggregation": "first" | "min" | "max" | "all" | "count" | "field_count" | "value_count",
        "field": "<field path>", // not needed when using the "count" aggregation
        "value": "<field_value>", // only when using the "value_count" aggregation
    },
    ...
  },
  "dtype": "array" | "object"
}

filter_by

The filter_by clause must be a valid JSON object that defines the filtering criteria. The structure of this clause is designed to accommodate complex filtering logic, including combinations of AND, OR, and NOT conditions. It is a tree that represents a boolean expression.

Leaf nodes represent a single condition that must be true for a variation to be included & must have the following keys:

  • field: Specifies the path to the field that the condition applies to. Nested fields can be referenced using a dot (.) as a separator (for example, data.color). Array indexes can be represented in square brackets (for example, data.colors[0])
  • value: The value that the specified field must match for the condition to be considered true.

Internal nodes represent boolean operations and can have one of the following keys:

  • and: An array of conditions that must all be true for a variation to be included. It represents the logical AND operation.
  • or: An array within the and condition that specifies alternative conditions. At least one of the conditions within the or array must be true. It represents the logical OR operation.
  • not: An object that negates the condition specified within it. It is used to exclude variations that match the specified condition. Represents the logical NOT operation.

Example

Consider a scenario where you want to filter variations to include only those that are either red or blue, but not in size "S." The filter_by clause for this scenario would look like this:

{
  "filter_by": {
    "and": [
      {
        "or": [
          {
            "field": "data.color",
            "value": "red"
          },
          {
            "field": "data.color",
            "value": "blue"
          }
        ]
      },
      {
        "not": {
          "field": "data.size",
          "value": "S"
        }
      }
    ]
  }
}

group_by

This is an optional array that specifies how variations should be grouped. Each object in the array must have the following properties:

  • name: [string] Any alias that will be used to refer to aggregated field values in the response.
  • field: [string] Path to the field in the variations' data that's used to group variations (for example, data.price). For nested paths object keys are separated by ., while array indices should be surrounded by square brackets (for example, data.stores[0]).

In typical e-commerce scenarios, each resulting group of variations accounts for one swatch in the result tile.

If group_by is omitted or an empty array, any aggregations that are specified in the values clause will happen on all variations without any grouping.

Example

Consider a scenario where you want group variations by color & size into swatches. The group_by clause could look like this:

{
    "group_by": [
        {"name": "color", "field": "data.color"},
        {"name": "size", "field": "data.size"}
    ],
}

values

This object specifies which fields you want to retrieve from each variation group and how to aggregate them.

Each key in the values object is an alias that will be used in the response, and its value is an object with the following properties:

  • aggregation: [string] The aggregation function to apply. Accepted values are first, min, max, all, count, field_count, and value_count.
  • field: [string] The path to the field that should be aggregated. This is not needed when using the count aggregation.
  • value: [boolean | integer | decimal | string]: Only used with the value_count aggregation to specify the value to count.

Example

Consider a scenario where you want to display the relevant image URL & minimum price when a user hovers over a swatch that represents a group of variations. The values clause could look like this:

{
    "values": {
        "image_url": {
            "field": "data.image_url",
            "aggregation": "first"
        },
        "min_price": {
            "field": "data.price",
            "aggregation": "min"
        }
    }
}

dtype

This specifies the data type of the variations_map that should be returned in the response. Accepted values are array and object. This affects how the grouped and aggregated data is structured in the response.

Aggregation functions

first

Returns the value from the first variation in the group. Use this when you simply want any single value from each group of variations as a representative of the group, (for example, image_url for a given swatch).

min

Returns the minimum value of the specified field across all variations in the group.

max

Returns the maximum value of the specified field across all variations in the group.

all

Returns all values of the specified field, one for each variation in the group.

count

Returns the number of variations in the group.

field_count

Returns the number of variations in the group that contain the specified field.

value_count

Returns the number of variations in the group that have the specified field equal to the specified value.

Example usage

Putting together all of the examples from the schema overview preceding, suppose a hypothetical scenario where:

  • We want to consider only variations that have either the in_stock: true or display_if_out_of_stock: true flags set.
  • We want to group variations by color & size, so that we can display one swatch per color & size combination
  • For each swatch, we are interested in any image_url, the lowest price across all variations that are represented by that swatch, as well as the highest price.

The variations_map parameter could look like the following:

{
  "filter_by": {
    "or": [
      { "field": "data.in_stock", "value": true },
      { "field": "data.display_if_out_of_stock", "value": true }
    ]
  },
  "group_by": [
    {
      "name": "color",
      "field": "data.color"
    },
    {
      "name": "size",
      "field": "data.size"
    }
  ],
  "values": {
    "main_image_url": {
      "aggregation": "first",
      "field": "data.image_url"
    },
    "min_price": {
      "aggregation": "min",
      "field": "data.price"
    },
    "max_price": {
      "aggregation": "max",
      "field": "data.price"
    }
  },
  "dtype": "array"
}

In this case, each item in the API response would have a variations_map attribute with a value that might look like the following:

{
  "response": {
    "result_sources": {},
    "facets": [],
    "groups": [],
    "results": [
      {
        "matched_terms": [],
        "data": {},
        "variations_map": [
          {
            "color": "red",
            "size": "S",
            "min_price": 10,
            "max_price": 15,
            "main_image_url": "https://example.com/best-shorts/red_s.jpg"
          },
          {
            "color": "red",
            "size": "M",
            "min_price": 10,
            "max_price": 15,
            "main_image_url": "https://example.com/best-shorts/red_m.jpg"
          },
          {
            "color": "blue",
            "size": "L",
            "min_price": 25,
            "max_price": 30,
            "main_image_url": "https://example.com/best-shorts/blue_l.jpg"
          }
        ]
      }
    ]
  }
}

Alternatively, you could change dtype to object, in which case the same data would be returned in the following format:

{
  "response": {
      "result_sources": {},
      "facets": [],
      "groups": [],
      "results": [
          {
              "matched_terms": [],
              "data": {},
              "variations_map": {
                  "red": {
                      "S": {
                          "min_price": 10,
                          "max_price": 15,
                          "main_image_url": "https://example.com/best-shorts/red_s.jpg"
                      },
                      "M": {
                          "min_price": 10,
                          "max_price": 15,
                          "main_image_url": "https://example.com/best-shorts/red_m.jpg"
                      }
                  },
                  "blue": {
                      "L": {
                          "min_price": 25,
                          "max_price": 30,
                          "main_image_url": "https://example.com/best-shorts/blue_l.jpg"
                      }
                  }
              }
          }
      ]
  }
}