Bloomreach Discovery Connector Schema Mapping
Introduction
This document explains how the response data from Bloomreach Discovery is mapped to the GraphQL Schema models served by the brX GraphQL Service.
For notation purposes, JSONPath expressions are used in this document to show how JSON object and properties are resolved mapped from the response data.
GraphQL Schema Models Overview
As explained in GraphQL Schema of GraphQL Service page, you can browse and explore the brX GraphQL Schema through the Playground UI or the HTML documents directly, but let's have a quick look at the core model schema snippets here.
In product searches through the Product search API, each product item data is represented by the Item GraphQL Schema model type, each product variant item by ItemVariant, and the whole result set with multiple product items by ItemsPageResult as shown below.
"Abstraction for both product item and product item variant" interface ItemLike { "The ItemId of a product item or product item variant" itemId: ItemId! "The display name of a product item or product item variant" displayName: String "The description of a product item or product item variant" description: String "The ImageSet of a product item or product item variant" imageSet: ImageSet "The listed price of a product item or product item variant" listPrice: Price "The purchase price of a product item or product item variant" purchasePrice: Price // ...SNIP... } "Product item abstraction" type Item implements ItemLike @key(fields: "itemId") { "The ItemId of a product item" itemId: ItemId! "The display name of a product item" displayName: String "The description of a product item" description: String "The ImageSet of a product item" imageSet: ImageSet "The listed price of a product item" listPrice: Price "The purchase price of a product item" purchasePrice: Price "Sale price range including the lowest and highest prices to put in the appropriate location" salePriceRange: [Float] "Price range including the lowest and highest prices to put in the appropriate location" priceRange: [Float] "All available product item variant dimension names. e.g, [{name:'color'}, {name:'size'}]" varAttrTypes: [AttributeType] "Product item variants of this product item" variants: [ItemVariant] // ...SNIP... } """ Item identifier that may hold multiple keys. e.g, the Commerce Backend Platform specific primary key and other alternate key(s) such as SKU, UPC, article number, etc. """ type ItemId { "The primary key identifier of a product item maintained by the Commerce Backend Platform" id: String! "The default alternate key identifier of a product item" code: String } "Product item variant abstraction" type ItemVariant implements ItemLike { "The ItemId of a product item variant" itemId: ItemId! "The display name of a product item variant" displayName: String "The description of a product item variant" description: String "Flag whether or not this is the master variant" master: Boolean "The ImageSet of a product item variant" imageSet: ImageSet "The listed price of a product item variant" listPrice: Price "The purchase price of a product item variant" purchasePrice: Price "The main product item which contains this product item variant" mainItem: Item "Product item variant dimension name-values mappings" varAttrs: [Attribute] // ...SNIP... } "Pagination-based product search result" type ItemsPageResult implements PageResult { "The offset index from which the search result starts" offset: Int! "The maximum size limit of the search result" limit: Int! "The item count of the search result" count: Int! "The total item count of the search result" total: Int! "The list of product items of the search result" items: [Item]! "Optional facet result available in this search" facetResult: FacetResult "Additional query info" queryHint: QueryHint // ...SNIP... }
And product category data is represented by the following type:
"Product category abstraction" type Category { "The identifier of this category" id: String! "The identifier of the parent category of this category" parentId: String! "The display name of this category" displayName: String! """ The optional category path to this category, delimited by '/'. Depending on the backend, some category items may appear in multiple tree nodes, in which case, this path property can be preferred to the id-parentId pair when constructing category tree nodes. """ path: String }
Also, response data from the Autosuggest API is represented by the following:
"Suggestion search result abstraction, including term suggestions and product item suggestions" type SuggestionResult { "Term suggestions" terms: [String]! "Product item suggestions" items: [Item] }
Product Data Mapping
The response data from the Product search API looks like the following example:
{ "response":{ "numFound":86, "start":0, "docs":[ { "sale_price":115.9, "price":115.9, "score":0.014999093, "description":"", "title":"PILOT SPORT A/S 3+", "url":"", "brand":"Michelin", "pid":"PILOT_SPORT_AS3PLUS", "thumb_image":"https://demo-images.s3-us-west-2.amazonaws.com/VESTRI_VIRTUAL_V2/92861.png", "sale_price_range":[ 115.9, 115.9 ], "price_range":[ 115.9, 115.9 ], "variants":[ { "sku_swatch_images":[ "92861" ], "sku_thumb_images":[ "https://demo-images.s3-us-west-2.amazonaws.com/VESTRI_VIRTUAL_V2/92861.png" ] }, { "sku_swatch_images":[ "56201" ], "sku_thumb_images":[ "https://demo-images.s3-us-west-2.amazonaws.com/VESTRI_VIRTUAL_V2/56201.png" ] }, { "sku_swatch_images":[ "80472" ], "sku_thumb_images":[ "https://demo-images.s3-us-west-2.amazonaws.com/VESTRI_VIRTUAL_V2/80472.png" ] } ] }, // ...SNIP... ] }, "facet_counts":{ "facet_ranges":{ }, "facet_fields":{ "category":[ { "count":15, "crumb":"/VPA_VEHICLE_ADDONS", "cat_name":"Vehicle Addons", "parent":"", "cat_id":"VPA_VEHICLE_ADDONS", "tree_path":"/VPA_VEHICLE_ADDONS,Vehicle Addons" }, { "count":14, "crumb":"/VPA_VEHICLE_ADDONS/VPA_VA_MCLASS", "cat_name":"M-Class", "parent":"VPA_VEHICLE_ADDONS", "cat_id":"VPA_VA_MCLASS", "tree_path":"/VPA_VEHICLE_ADDONS,Vehicle Addons/VPA_VA_MCLASS,M-Class" }, { "count":10, "crumb":"/VPA_VEHICLE_ADDONS/VPA_VA_T50", "cat_name":"T50", "parent":"VPA_VEHICLE_ADDONS", "cat_id":"VPA_VA_T50", "tree_path":"/VPA_VEHICLE_ADDONS,Vehicle Addons/VPA_VA_T50,T50" }, { "count":28, "crumb":"/VESTRI_BM_APPAREL", "cat_name":"Apparel", "parent":"", "cat_id":"VESTRI_BM_APPAREL", "tree_path":"/VESTRI_BM_APPAREL,Apparel" }, { "count":9, "crumb":"/VPA_VEHICLE_ADDONS/VPA_VA_XCLASS", "cat_name":"X-Class", "parent":"VPA_VEHICLE_ADDONS", "cat_id":"VPA_VA_XCLASS", "tree_path":"/VPA_VEHICLE_ADDONS,Vehicle Addons/VPA_VA_XCLASS,X-Class" }, // ...SNIP... ], "brand":[ { "count":80, "name":"Vestri" }, // ...SNIP... ], "colors":[ { "count":18, "name":"black" }, { "count":19, "name":"blue" }, // ...SNIP... ], // ...SNIP... }, // ...SNIP... }, // ...SNIP... }
When finding multiple product items data (e.g, GraphQL queries such as findItemsByKeyword, findItemsByCategory, etc.), the main response data object is of type ItemsPageResult, being mapped as follows:
Field of ItemsPageResult | Resolving JSONPath expression from response | Notes |
offset |
$.response.start |
|
limit |
|
Set to the limit query input parameter. |
count |
($.response.docs).length |
|
total |
$.response.numFound |
|
items |
|
See the Mapping for Item table below. |
facetResult |
$.facet_count.facet_fields |
Constructs facet navigation information as FacetResult schema type, using the resolved facet fields. |
queryHint |
{ |
See the following pages for detail: |
Each product item data in the $.response.docs is mapped to a Item model in ItemsPageResult.items array as follows:
Field of Item | JSONPath on $.response.docs[*] | Notes |
itemId |
{ "id": pid, "code": variants[0].sku_swatch_images[0] } |
itemId field consists of id and code properties, each of which is extracted from the corresponding JSONPath expression. If the code property is not resolved, the pid value for the id field is used for the property, too. |
displayName |
title | |
description |
description | |
imageSet |
{ |
|
listPrice |
price | |
purchasePrice |
sale_price | |
salePriceRange |
sale_price_range | |
priceRange |
price_range | |
variants |
variants | See the Mapping for ItemVariant table below for details. |
customAttrs |
See the answer for the question, "How can I include extra custom fields from the brSM API response?" in the FAQ page. |
Field of ItemVariant | JSONPath on $.response.docs[*].variants[*] | Notes |
itemId |
{ "id": pid, "code": variants[0].sku_swatch_images[0] } |
itemId field consists of id and code properties, each of which is extracted from the corresponding JSONPath expression. If the code property is not resolved, the pid value for the id field is used for the property, too. |
displayName |
Same as the parent product Item's displayName property. | |
description |
Same as the parent product Item's description property. | |
imageSet |
{ |
|
listPrice |
Same as the parent product Item's listPrice property. | |
purchasePrice |
Same as the parent product Item's purchasePrice property. | |
mainItem |
The parent product Item which has all variants. | |
customAttrs |
See the answer for the question, "How can I include extra custom fields from the Bloomreach Discovery API response?" in the FAQ page. |
Category Data Mapping
When finding categories (i.e. findCategories GraphQL query), the main response data object is an array of Category models. For a single category finding (i.e. findCategoryByID GraphQL query), it is a single Category model if found.
Internally the queries use the same Product search API and the response looks like the following:
{ "response":{ "numFound":86, "start":1, "docs":[ // ...SNIP... ] }, "facet_counts":{ "facet_ranges":{ }, "facet_fields":{ "category":[ { "count":15, "crumb":"/VPA_VEHICLE_ADDONS", "cat_name":"Vehicle Addons", "parent":"", "cat_id":"VPA_VEHICLE_ADDONS", "tree_path":"/VPA_VEHICLE_ADDONS,Vehicle Addons" }, { "count":14, "crumb":"/VPA_VEHICLE_ADDONS/VPA_VA_MCLASS", "cat_name":"M-Class", "parent":"VPA_VEHICLE_ADDONS", "cat_id":"VPA_VA_MCLASS", "tree_path":"/VPA_VEHICLE_ADDONS,Vehicle Addons/VPA_VA_MCLASS,M-Class" }, { "count":10, "crumb":"/VPA_VEHICLE_ADDONS/VPA_VA_T50", "cat_name":"T50", "parent":"VPA_VEHICLE_ADDONS", "cat_id":"VPA_VA_T50", "tree_path":"/VPA_VEHICLE_ADDONS,Vehicle Addons/VPA_VA_T50,T50" }, { "count":28, "crumb":"/VESTRI_BM_APPAREL", "cat_name":"Apparel", "parent":"", "cat_id":"VESTRI_BM_APPAREL", "tree_path":"/VESTRI_BM_APPAREL,Apparel" }, { "count":9, "crumb":"/VPA_VEHICLE_ADDONS/VPA_VA_XCLASS", "cat_name":"X-Class", "parent":"VPA_VEHICLE_ADDONS", "cat_id":"VPA_VA_XCLASS", "tree_path":"/VPA_VEHICLE_ADDONS,Vehicle Addons/VPA_VA_XCLASS,X-Class" }, // ...SNIP... ], // ...SNIP... }, // ...SNIP... }, // ...SNIP... }
Each category item data in the $.response.facet_counts.facet_fields.category array is mapped to a Category model like the following:
Field of Category | JSONPath on $.response.facet_counts.facet_fields.category[*] | Notes |
id |
cat_id | |
parentId |
parent | |
displayName |
cat_name | |
path |
tree_path |
Autosuggest Data Mapping
The response data from the Autosuggest API looks like the following example:
{ "queryContext":{ "originalQuery":"b" }, "suggestionGroups":[ { "catalogName":"example_com", "view":"default", "querySuggestions":[ { "query":"boots", "displayText":"boots" }, { "query":"backpack", "displayText":"backpack" }, { "query":"bench", "displayText":"bench" }, // ...SNIP... ], "searchSuggestions":[ { "sale_price":40, "url":"https://www.example.com/not-available/craftsman-safety-boots-size-8/5055160047421_BQ.prd?_br_psugg_q=boots", "pid":"5055160047421_BQ", "thumb_image":"//king.scene7.com/is/image/King/productTemplate?$baseImage=King/5055160047421_01bq", "title":"Craftsman Safety boots, Size 8" }, { "sale_price":25, "url":"https://www.example.com/not-available/site-granite-grey-trainer-boots-size-10/289361_BQ.prd?_br_psugg_q=boots", "pid":"289361_BQ", "thumb_image":"//king.scene7.com/is/image/King/productTemplate?$baseImage=King/5055338404995_01bq", "title":"Site Granite Grey Trainer boots, Size 10" }, { "sale_price":40, "url":"https://www.example.com/not-available/site-brown-mudguard-dealer-boots-size-8/3663602605942_BQ.prd?_br_psugg_q=boots", "pid":"3663602605942_BQ", "thumb_image":"//king.scene7.com/is/image/King/productTemplate?$baseImage=King/3663602605942_01bq", "title":"Site Brown Mudguard Dealer boots, Size 8" }, // ...SNIP... ], // ...SNIP... } ] }
When looking up suggestions (i.e. findSuggestions GraphQL query), the main response data object is of type SuggestionResult, being mapped as follows:
Field of SuggestionResult | Resolving JSONPath expression from response | Notes |
terms |
$.suggestionGroups[*].querySuggestions[*].query | |
items |
$.suggestionGroups[*].searchSuggestions[*] | See the Mapping for Item table above for detail on how each product item is mapped. |