From a620e5b57c4289c610b1a54badc269680ee9306a Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Wed, 9 Jun 2021 18:18:18 +0200 Subject: [PATCH 1/5] feat(getFacetValues): process facetOrdering DX-2075 --- src/SearchResults/index.js | 134 +- .../getFacetValues-facetOrdering.js | 1486 +++++++++++++++++ .../getFacetValues/disjunctive.json | 2 +- .../getRefinements/hierarchical-cards.json | 5 +- 4 files changed, 1598 insertions(+), 29 deletions(-) create mode 100644 test/spec/SearchResults/getFacetValues-facetOrdering.js diff --git a/src/SearchResults/index.js b/src/SearchResults/index.js index 9747ba755..015e69675 100644 --- a/src/SearchResults/index.js +++ b/src/SearchResults/index.js @@ -659,20 +659,30 @@ function extractNormalizedFacetValues(results, attribute) { } /** - * Sort nodes of a hierarchical facet results + * Sort nodes of a hierarchical or disjunctive facet results * @private - * @param {HierarchicalFacet} node node to upon which we want to apply the sort + * @param {function} sortFn + * @param {HierarchicalFacet|Array} node node to upon which we want to apply the sort + * @param {string[]} names attribute names + * @param {number} [level=0] current index in the names array */ -function recSort(sortFn, node) { +function recSort(sortFn, node, names, level) { + level = level || 0; + + if (Array.isArray(node)) { + return sortFn(node, names[level]); + } + if (!node.data || node.data.length === 0) { return node; } var children = node.data.map(function(childNode) { - return recSort(sortFn, childNode); + return recSort(sortFn, childNode, names, level + 1); }); - var sortedChildren = sortFn(children); - var newNode = merge({}, node, {data: sortedChildren}); + var sortedChildren = sortFn(children, names[level]); + var newNode = merge({}, node); + newNode.data = sortedChildren; return newNode; } @@ -682,6 +692,66 @@ function vanillaSortFn(order, data) { return data.sort(order); } +/** + * @typedef FacetOrdering + * @type {Object} + * @property {string[]} [order] + * @property {'count' | 'alpha' | 'hidden'} [sortRemainingBy] + */ + +/** + * Sorts facet arrays via their facet ordering + * @param {Array} facetValues the values + * @param {FacetOrdering} facetOrdering the ordering + * @returns {Array} + */ +function sortViaFacetOrdering(facetValues, facetOrdering) { + var pinnedFacets = []; + var unpinnedFacets = []; + + var pinned = facetOrdering.order || []; + var reversePinned = pinned.reduce(function(acc, name, i) { + acc[name] = i; + return acc; + }, {}); + + facetValues.forEach(function(item) { + if (reversePinned[item.name] !== undefined) { + pinnedFacets[reversePinned[item.name]] = item; + } else { + unpinnedFacets.push(item); + } + }); + + var sortRemainingBy = facetOrdering.sortRemainingBy; + var ordering; + if (sortRemainingBy === 'hidden') { + return pinnedFacets; + } else if (sortRemainingBy === 'alpha') { + ordering = [['name'], ['asc']]; + } else { + ordering = [['count'], ['desc']]; + } + + return pinnedFacets.concat( + orderBy(unpinnedFacets, ordering[0], ordering[1]) + ); +} + +/** + * @param {SearchResults} results a results class (this) + * @param {string} attribute the attribute to retrieve ordering of + * @returns {FacetOrdering=} + */ +function getFacetOrdering(results, attribute) { + return ( + results.renderingContent && + results.renderingContent.facetOrdering && + results.renderingContent.facetOrdering.values && + results.renderingContent.facetOrdering.values[attribute] + ); +} + /** * Get a the list of values for a given facet attribute. Those values are sorted * refinement first, descending count (bigger value on top), and name ascending @@ -694,6 +764,9 @@ function vanillaSortFn(order, data) { * might not be respected if you have facet values that are already refined. * @param {string} attribute attribute name * @param {object} opts configuration options. + * @param {boolean} [opts.facetOrdering=false] + * Force the use of facetOrdering from the result if a sortBy is present. If + * sortBy isn't present, facetOrdering will be used automatically. * @param {Array. | function} opts.sortBy * When using strings, it consists of * the name of the [FacetValue](#SearchResults.FacetValue) or the @@ -735,28 +808,37 @@ SearchResults.prototype.getFacetValues = function(attribute, opts) { var options = defaultsPure({}, opts, {sortBy: SearchResults.DEFAULT_SORT}); - if (Array.isArray(options.sortBy)) { - var order = formatSort(options.sortBy, SearchResults.DEFAULT_SORT); - if (Array.isArray(facetValues)) { - return orderBy(facetValues, order[0], order[1]); - } - // If facetValues is not an array, it's an object thus a hierarchical facet object - return recSort(function(hierarchicalFacetValues) { - return orderBy(hierarchicalFacetValues, order[0], order[1]); - }, facetValues); - } else if (typeof options.sortBy === 'function') { - if (Array.isArray(facetValues)) { - return facetValues.sort(options.sortBy); + var results = this; + var attributes; + if (Array.isArray(facetValues)) { + attributes = [attribute]; + } else { + var config = results._state.getHierarchicalFacetByName(facetValues.name); + attributes = config.attributes; + } + + return recSort(function(data, facetName) { + // if no sortBy is given, attempt to sort based on facetOrdering + // if it is given, we still allow to sort via facet ordering first + if (!opts || !opts.sortBy || opts.facetOrdering) { + var facetOrdering = getFacetOrdering(results, facetName); + if (Boolean(facetOrdering)) { + return sortViaFacetOrdering(data, facetOrdering); + } } - // If facetValues is not an array, it's an object thus a hierarchical facet object - return recSort(function(data) { + + if (Array.isArray(options.sortBy)) { + var order = formatSort(options.sortBy, SearchResults.DEFAULT_SORT); + + return orderBy(data, order[0], order[1]); + } else if (typeof options.sortBy === 'function') { return vanillaSortFn(options.sortBy, data); - }, facetValues); - } - throw new Error( - 'options.sortBy is optional but if defined it must be ' + - 'either an array of string (predicates) or a sorting function' - ); + } + throw new Error( + 'options.sortBy is optional but if defined it must be ' + + 'either an array of string (predicates) or a sorting function' + ); + }, facetValues, attributes); }; /** diff --git a/test/spec/SearchResults/getFacetValues-facetOrdering.js b/test/spec/SearchResults/getFacetValues-facetOrdering.js new file mode 100644 index 000000000..0a5c39656 --- /dev/null +++ b/test/spec/SearchResults/getFacetValues-facetOrdering.js @@ -0,0 +1,1486 @@ +'use strict'; + +var SearchResults = require('../../../src/SearchResults'); +var SearchParameters = require('../../../src/SearchParameters'); + +describe('disjunctive facet', function() { + test.each([ + [ + 'nothing pinned', + { + values: { + brand: { + order: [] + } + } + }, + [ + {count: 551, isRefined: false, name: 'Insignia™'}, + {count: 511, isRefined: false, name: 'Samsung'}, + {count: 386, isRefined: true, name: 'Apple'} + ] + ], + [ + 'all pinned', + { + values: { + brand: { + order: ['Samsung', 'Apple', 'Insignia™'] + } + } + }, + [ + {count: 511, isRefined: false, name: 'Samsung'}, + {count: 386, isRefined: true, name: 'Apple'}, + {count: 551, isRefined: false, name: 'Insignia™'} + ] + ], + [ + 'one item pinned (implicit sort)', + { + values: { + brand: { + order: ['Samsung'] + } + } + }, + [ + {count: 511, isRefined: false, name: 'Samsung'}, + {count: 551, isRefined: false, name: 'Insignia™'}, + {count: 386, isRefined: true, name: 'Apple'} + ] + ], + [ + 'one item pinned (sort by count)', + { + values: { + brand: { + order: ['Samsung'], + sortRemainingBy: 'count' + } + } + }, + [ + {count: 511, isRefined: false, name: 'Samsung'}, + {count: 551, isRefined: false, name: 'Insignia™'}, + {count: 386, isRefined: true, name: 'Apple'} + ] + ], + [ + 'one item pinned (sort by alpha)', + { + values: { + brand: { + order: ['Samsung'], + sortRemainingBy: 'alpha' + } + } + }, + [ + {count: 511, isRefined: false, name: 'Samsung'}, + {count: 386, isRefined: true, name: 'Apple'}, + {count: 551, isRefined: false, name: 'Insignia™'} + ] + ], + [ + 'one item pinned (sort by hidden)', + { + values: { + brand: { + order: ['Samsung'], + sortRemainingBy: 'hidden' + } + } + }, + [{count: 511, isRefined: false, name: 'Samsung'}] + ] + ])('%p', function(_name, facetOrdering, expected) { + var data = require('./getFacetValues/disjunctive.json'); + var order = { + renderingContent: { + facetOrdering: facetOrdering + } + }; + var results = data.content.results.slice(); + results[0] = Object.assign(order, results[0]); + + var searchParams = new SearchParameters(data.state); + var result = new SearchResults(searchParams, results); + + var facetValues = result.getFacetValues('brand'); + + expect(facetValues).toEqual(expected); + }); + + test('sortBy overrides facetOrdering', function() { + var data = require('./getFacetValues/disjunctive.json'); + var order = { + renderingContent: { + facetOrdering: { + values: { + brand: { + order: ['Samsung', 'Apple', 'Insignia™'] + } + } + } + } + }; + var results = data.content.results.slice(); + results[0] = Object.assign(order, results[0]); + + var searchParams = new SearchParameters(data.state); + var result = new SearchResults(searchParams, results); + + var facetValues = result.getFacetValues('brand', {sortBy: ['name:desc']}); + + var expected = [ + {count: 511, isRefined: false, name: 'Samsung'}, + {count: 551, isRefined: false, name: 'Insignia™'}, + {count: 386, isRefined: true, name: 'Apple'} + ]; + + expect(facetValues).toEqual(expected); + }); + + test('facetOrdering: true overrides sortBy', function() { + var data = require('./getFacetValues/disjunctive.json'); + var order = { + renderingContent: { + facetOrdering: { + values: { + brand: { + order: ['Samsung', 'Apple', 'Insignia™'] + } + } + } + } + }; + var results = data.content.results.slice(); + results[0] = Object.assign(order, results[0]); + + var searchParams = new SearchParameters(data.state); + var result = new SearchResults(searchParams, results); + + var facetValues = result.getFacetValues('brand', { + sortBy: ['name:desc'], + facetOrdering: true + }); + + var expected = [ + {count: 511, isRefined: false, name: 'Samsung'}, + {count: 386, isRefined: true, name: 'Apple'}, + {count: 551, isRefined: false, name: 'Insignia™'} + ]; + + expect(facetValues).toEqual(expected); + }); + + test('without facetOrdering, nor sortBy', function() { + var data = require('./getFacetValues/disjunctive.json'); + var order = { + renderingContent: {} + }; + var results = data.content.results.slice(); + results[0] = Object.assign(order, results[0]); + + var searchParams = new SearchParameters(data.state); + var result = new SearchResults(searchParams, results); + + var facetValues = result.getFacetValues('brand'); + + var expected = [ + {count: 386, isRefined: true, name: 'Apple'}, + {count: 551, isRefined: false, name: 'Insignia™'}, + {count: 511, isRefined: false, name: 'Samsung'} + ]; + + expect(facetValues).toEqual(expected); + }); +}); + +describe('hierarchical facet', function() { + test('empty facet ordering', function() { + var data = require('./getRefinements/hierarchical-cards.json'); + var order = { + renderingContent: { + facetOrdering: {} + } + }; + var results = data.content.results.slice(); + results[0] = Object.assign(order, results[0]); + + var searchParams = new SearchParameters(data.state); + var result = new SearchResults(searchParams, results); + + var facetValues = result.getFacetValues('hierarchicalCategories'); + + var expected = { + name: 'hierarchicalCategories', + count: null, + isRefined: true, + path: null, + exhaustive: true, + data: [ + { + name: 'Best Buy Gift Cards', + path: 'Best Buy Gift Cards', + count: 80, + isRefined: true, + exhaustive: true, + data: [ + { + count: 17, + data: null, + exhaustive: true, + isRefined: true, + name: 'Entertainment Gift Cards', + path: 'Best Buy Gift Cards > Entertainment Gift Cards' + }, + { + name: 'Swag Gift Cards', + path: 'Best Buy Gift Cards > Swag Gift Cards', + count: 20, + isRefined: false, + exhaustive: true, + data: null + } + ] + }, + { + name: 'Cell Phones', + path: 'Cell Phones', + count: 1920, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Computers & Tablets', + path: 'Computers & Tablets', + count: 1858, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Appliances', + path: 'Appliances', + count: 1533, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Audio', + path: 'Audio', + count: 1010, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Cameras & Camcorders', + path: 'Cameras & Camcorders', + count: 753, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'TV & Home Theater', + path: 'TV & Home Theater', + count: 617, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Car Electronics & GPS', + path: 'Car Electronics & GPS', + count: 509, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Health, Fitness & Beauty', + path: 'Health, Fitness & Beauty', + count: 385, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Office & School Supplies', + path: 'Office & School Supplies', + count: 302, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Video Games', + path: 'Video Games', + count: 178, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Housewares', + path: 'Housewares', + count: 135, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Office Electronics', + path: 'Office Electronics', + count: 122, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Toys, Games & Drones', + path: 'Toys, Games & Drones', + count: 104, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Connected Home', + path: 'Connected Home', + count: 96, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Telephones & Communication', + path: 'Telephones & Communication', + count: 76, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Wearable Technology', + path: 'Wearable Technology', + count: 68, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Name Brands', + path: 'Name Brands', + count: 55, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Paper', + path: 'Paper', + count: 48, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Musical Instruments', + path: 'Musical Instruments', + count: 40, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Household Essentials', + path: 'Household Essentials', + count: 32, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Scanners, Faxes & Copiers', + path: 'Scanners, Faxes & Copiers', + count: 25, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Office Furniture & Storage', + path: 'Office Furniture & Storage', + count: 14, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Movies & Music', + path: 'Movies & Music', + count: 13, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Magnolia Home Theater', + path: 'Magnolia Home Theater', + count: 10, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Furniture & Decor', + path: 'Furniture & Decor', + count: 6, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Batteries & Power', + path: 'Batteries & Power', + count: 5, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Carfi Instore Only', + path: 'Carfi Instore Only', + count: 4, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Home', + path: 'Home', + count: 1, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Microwaves', + path: 'Microwaves', + count: 1, + isRefined: false, + exhaustive: true, + data: null + } + ] + }; + + expect(facetValues).toEqual(expected); + }); + + test('root pinned (no sortRemainingBy)', function() { + var data = require('./getRefinements/hierarchical-cards.json'); + var order = { + renderingContent: { + facetOrdering: { + values: { + 'hierarchicalCategories.lvl0': { + order: ['Appliances', 'Audio', 'Scanners, Faxes & Copiers'] + } + } + } + } + }; + var results = data.content.results.slice(); + results[0] = Object.assign(order, results[0]); + + var searchParams = new SearchParameters(data.state); + var result = new SearchResults(searchParams, results); + + var facetValues = result.getFacetValues('hierarchicalCategories'); + + var expected = { + name: 'hierarchicalCategories', + count: null, + isRefined: true, + path: null, + exhaustive: true, + data: [ + { + name: 'Appliances', + path: 'Appliances', + count: 1533, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Audio', + path: 'Audio', + count: 1010, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Scanners, Faxes & Copiers', + path: 'Scanners, Faxes & Copiers', + count: 25, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Cell Phones', + path: 'Cell Phones', + count: 1920, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Computers & Tablets', + path: 'Computers & Tablets', + count: 1858, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Cameras & Camcorders', + path: 'Cameras & Camcorders', + count: 753, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'TV & Home Theater', + path: 'TV & Home Theater', + count: 617, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Car Electronics & GPS', + path: 'Car Electronics & GPS', + count: 509, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Health, Fitness & Beauty', + path: 'Health, Fitness & Beauty', + count: 385, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Office & School Supplies', + path: 'Office & School Supplies', + count: 302, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Video Games', + path: 'Video Games', + count: 178, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Housewares', + path: 'Housewares', + count: 135, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Office Electronics', + path: 'Office Electronics', + count: 122, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Toys, Games & Drones', + path: 'Toys, Games & Drones', + count: 104, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Connected Home', + path: 'Connected Home', + count: 96, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Best Buy Gift Cards', + path: 'Best Buy Gift Cards', + count: 80, + isRefined: true, + exhaustive: true, + data: [ + { + count: 17, + data: null, + exhaustive: true, + isRefined: true, + name: 'Entertainment Gift Cards', + path: 'Best Buy Gift Cards > Entertainment Gift Cards' + }, + { + name: 'Swag Gift Cards', + path: 'Best Buy Gift Cards > Swag Gift Cards', + count: 20, + isRefined: false, + exhaustive: true, + data: null + } + ] + }, + { + name: 'Telephones & Communication', + path: 'Telephones & Communication', + count: 76, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Wearable Technology', + path: 'Wearable Technology', + count: 68, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Name Brands', + path: 'Name Brands', + count: 55, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Paper', + path: 'Paper', + count: 48, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Musical Instruments', + path: 'Musical Instruments', + count: 40, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Household Essentials', + path: 'Household Essentials', + count: 32, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Office Furniture & Storage', + path: 'Office Furniture & Storage', + count: 14, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Movies & Music', + path: 'Movies & Music', + count: 13, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Magnolia Home Theater', + path: 'Magnolia Home Theater', + count: 10, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Furniture & Decor', + path: 'Furniture & Decor', + count: 6, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Batteries & Power', + path: 'Batteries & Power', + count: 5, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Carfi Instore Only', + path: 'Carfi Instore Only', + count: 4, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Home', + path: 'Home', + count: 1, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Microwaves', + path: 'Microwaves', + count: 1, + isRefined: false, + exhaustive: true, + data: null + } + ] + }; + + expect(facetValues).toEqual(expected); + }); + + test('root pinned (sortRemainingBy count)', function() { + var data = require('./getRefinements/hierarchical-cards.json'); + var order = { + renderingContent: { + facetOrdering: { + values: { + 'hierarchicalCategories.lvl0': { + order: ['Appliances', 'Audio', 'Scanners, Faxes & Copiers'], + sortRemainingBy: 'count' + } + } + } + } + }; + var results = data.content.results.slice(); + results[0] = Object.assign(order, results[0]); + + var searchParams = new SearchParameters(data.state); + var result = new SearchResults(searchParams, results); + + var facetValues = result.getFacetValues('hierarchicalCategories'); + + var expected = { + name: 'hierarchicalCategories', + count: null, + isRefined: true, + path: null, + exhaustive: true, + data: [ + { + name: 'Appliances', + path: 'Appliances', + count: 1533, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Audio', + path: 'Audio', + count: 1010, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Scanners, Faxes & Copiers', + path: 'Scanners, Faxes & Copiers', + count: 25, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Cell Phones', + path: 'Cell Phones', + count: 1920, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Computers & Tablets', + path: 'Computers & Tablets', + count: 1858, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Cameras & Camcorders', + path: 'Cameras & Camcorders', + count: 753, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'TV & Home Theater', + path: 'TV & Home Theater', + count: 617, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Car Electronics & GPS', + path: 'Car Electronics & GPS', + count: 509, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Health, Fitness & Beauty', + path: 'Health, Fitness & Beauty', + count: 385, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Office & School Supplies', + path: 'Office & School Supplies', + count: 302, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Video Games', + path: 'Video Games', + count: 178, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Housewares', + path: 'Housewares', + count: 135, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Office Electronics', + path: 'Office Electronics', + count: 122, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Toys, Games & Drones', + path: 'Toys, Games & Drones', + count: 104, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Connected Home', + path: 'Connected Home', + count: 96, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Best Buy Gift Cards', + path: 'Best Buy Gift Cards', + count: 80, + isRefined: true, + exhaustive: true, + data: [ + { + count: 17, + data: null, + exhaustive: true, + isRefined: true, + name: 'Entertainment Gift Cards', + path: 'Best Buy Gift Cards > Entertainment Gift Cards' + }, + { + name: 'Swag Gift Cards', + path: 'Best Buy Gift Cards > Swag Gift Cards', + count: 20, + isRefined: false, + exhaustive: true, + data: null + } + ] + }, + { + name: 'Telephones & Communication', + path: 'Telephones & Communication', + count: 76, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Wearable Technology', + path: 'Wearable Technology', + count: 68, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Name Brands', + path: 'Name Brands', + count: 55, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Paper', + path: 'Paper', + count: 48, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Musical Instruments', + path: 'Musical Instruments', + count: 40, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Household Essentials', + path: 'Household Essentials', + count: 32, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Office Furniture & Storage', + path: 'Office Furniture & Storage', + count: 14, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Movies & Music', + path: 'Movies & Music', + count: 13, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Magnolia Home Theater', + path: 'Magnolia Home Theater', + count: 10, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Furniture & Decor', + path: 'Furniture & Decor', + count: 6, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Batteries & Power', + path: 'Batteries & Power', + count: 5, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Carfi Instore Only', + path: 'Carfi Instore Only', + count: 4, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Home', + path: 'Home', + count: 1, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Microwaves', + path: 'Microwaves', + count: 1, + isRefined: false, + exhaustive: true, + data: null + } + ] + }; + + expect(facetValues).toEqual(expected); + }); + + test('root pinned (sortRemainingBy alpha)', function() { + var data = require('./getRefinements/hierarchical-cards.json'); + var order = { + renderingContent: { + facetOrdering: { + values: { + 'hierarchicalCategories.lvl0': { + order: ['Appliances', 'Audio', 'Scanners, Faxes & Copiers'], + sortRemainingBy: 'alpha' + } + } + } + } + }; + var results = data.content.results.slice(); + results[0] = Object.assign(order, results[0]); + + var searchParams = new SearchParameters(data.state); + var result = new SearchResults(searchParams, results); + + var facetValues = result.getFacetValues('hierarchicalCategories'); + + var expected = { + name: 'hierarchicalCategories', + count: null, + isRefined: true, + path: null, + exhaustive: true, + data: [ + // pinned + { + name: 'Appliances', + path: 'Appliances', + count: 1533, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Audio', + path: 'Audio', + count: 1010, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Scanners, Faxes & Copiers', + path: 'Scanners, Faxes & Copiers', + count: 25, + isRefined: false, + exhaustive: true, + data: null + }, + // ordered alphabetically + { + name: 'Batteries & Power', + path: 'Batteries & Power', + count: 5, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Best Buy Gift Cards', + path: 'Best Buy Gift Cards', + count: 80, + isRefined: true, + exhaustive: true, + data: [ + { + count: 17, + data: null, + exhaustive: true, + isRefined: true, + name: 'Entertainment Gift Cards', + path: 'Best Buy Gift Cards > Entertainment Gift Cards' + }, + { + name: 'Swag Gift Cards', + path: 'Best Buy Gift Cards > Swag Gift Cards', + count: 20, + isRefined: false, + exhaustive: true, + data: null + } + ] + }, + { + name: 'Cameras & Camcorders', + path: 'Cameras & Camcorders', + count: 753, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Car Electronics & GPS', + path: 'Car Electronics & GPS', + count: 509, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Carfi Instore Only', + path: 'Carfi Instore Only', + count: 4, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Cell Phones', + path: 'Cell Phones', + count: 1920, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Computers & Tablets', + path: 'Computers & Tablets', + count: 1858, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Connected Home', + path: 'Connected Home', + count: 96, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Furniture & Decor', + path: 'Furniture & Decor', + count: 6, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Health, Fitness & Beauty', + path: 'Health, Fitness & Beauty', + count: 385, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Home', + path: 'Home', + count: 1, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Household Essentials', + path: 'Household Essentials', + count: 32, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Housewares', + path: 'Housewares', + count: 135, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Magnolia Home Theater', + path: 'Magnolia Home Theater', + count: 10, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Microwaves', + path: 'Microwaves', + count: 1, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Movies & Music', + path: 'Movies & Music', + count: 13, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Musical Instruments', + path: 'Musical Instruments', + count: 40, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Name Brands', + path: 'Name Brands', + count: 55, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Office & School Supplies', + path: 'Office & School Supplies', + count: 302, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Office Electronics', + path: 'Office Electronics', + count: 122, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Office Furniture & Storage', + path: 'Office Furniture & Storage', + count: 14, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Paper', + path: 'Paper', + count: 48, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'TV & Home Theater', + path: 'TV & Home Theater', + count: 617, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Telephones & Communication', + path: 'Telephones & Communication', + count: 76, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Toys, Games & Drones', + path: 'Toys, Games & Drones', + count: 104, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Video Games', + path: 'Video Games', + count: 178, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Wearable Technology', + path: 'Wearable Technology', + count: 68, + isRefined: false, + exhaustive: true, + data: null + } + ] + }; + + expect(facetValues).toEqual(expected); + }); + + test('root pinned (sortRemainingBy hidden)', function() { + var data = require('./getRefinements/hierarchical-cards.json'); + var order = { + renderingContent: { + facetOrdering: { + values: { + 'hierarchicalCategories.lvl0': { + order: ['Appliances', 'Audio', 'Scanners, Faxes & Copiers'], + sortRemainingBy: 'hidden' + } + } + } + } + }; + var results = data.content.results.slice(); + results[0] = Object.assign(order, results[0]); + + var searchParams = new SearchParameters(data.state); + var result = new SearchResults(searchParams, results); + + var facetValues = result.getFacetValues('hierarchicalCategories'); + + var expected = { + name: 'hierarchicalCategories', + count: null, + isRefined: true, + path: null, + exhaustive: true, + data: [ + { + name: 'Appliances', + path: 'Appliances', + count: 1533, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Audio', + path: 'Audio', + count: 1010, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Scanners, Faxes & Copiers', + path: 'Scanners, Faxes & Copiers', + count: 25, + isRefined: false, + exhaustive: true, + data: null + } + ] + }; + + expect(facetValues).toEqual(expected); + }); + + test('two levels pinned (sortRemainingBy count)', function() { + var data = require('./getRefinements/hierarchical-cards.json'); + var order = { + renderingContent: { + facetOrdering: { + values: { + 'hierarchicalCategories.lvl0': { + order: ['Best Buy Gift Cards'], + sortRemainingBy: 'hidden' + }, + 'hierarchicalCategories.lvl1': { + order: ['Swag Gift Cards'], + sortRemainingBy: 'count' + } + } + } + } + }; + var results = data.content.results.slice(); + results[0] = Object.assign(order, results[0]); + + var searchParams = new SearchParameters(data.state); + var result = new SearchResults(searchParams, results); + + var facetValues = result.getFacetValues('hierarchicalCategories'); + + var expected = { + name: 'hierarchicalCategories', + count: null, + isRefined: true, + path: null, + exhaustive: true, + data: [ + { + name: 'Best Buy Gift Cards', + path: 'Best Buy Gift Cards', + count: 80, + isRefined: true, + exhaustive: true, + data: [ + { + name: 'Swag Gift Cards', + path: 'Best Buy Gift Cards > Swag Gift Cards', + count: 20, + isRefined: false, + exhaustive: true, + data: null + }, + { + name: 'Entertainment Gift Cards', + path: 'Best Buy Gift Cards > Entertainment Gift Cards', + count: 17, + isRefined: true, + exhaustive: true, + data: null + } + ] + } + ] + }; + + expect(facetValues).toEqual(expected); + }); +}); diff --git a/test/spec/SearchResults/getFacetValues/disjunctive.json b/test/spec/SearchResults/getFacetValues/disjunctive.json index 06aff5c27..2248cfab9 100644 --- a/test/spec/SearchResults/getFacetValues/disjunctive.json +++ b/test/spec/SearchResults/getFacetValues/disjunctive.json @@ -1128,4 +1128,4 @@ "page": 0 }, "error": null -} \ No newline at end of file +} diff --git a/test/spec/SearchResults/getRefinements/hierarchical-cards.json b/test/spec/SearchResults/getRefinements/hierarchical-cards.json index 671aa6cd9..724e084ad 100644 --- a/test/spec/SearchResults/getRefinements/hierarchical-cards.json +++ b/test/spec/SearchResults/getRefinements/hierarchical-cards.json @@ -937,7 +937,8 @@ "Best Buy Gift Cards": 80 }, "hierarchicalCategories.lvl1": { - "Best Buy Gift Cards > Entertainment Gift Cards": 17 + "Best Buy Gift Cards > Entertainment Gift Cards": 17, + "Best Buy Gift Cards > Swag Gift Cards": 20 } }, "exhaustiveFacetsCount": true, @@ -1031,4 +1032,4 @@ "page": 0 }, "error": null -} \ No newline at end of file +} From 949d21d6f6ed463b39522a0a81199b11c715747f Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Thu, 10 Jun 2021 09:44:16 +0200 Subject: [PATCH 2/5] fix: behave correctly on facetOrdering: false --- src/SearchResults/index.js | 12 ++++--- .../getFacetValues-facetOrdering.js | 32 +++++++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/SearchResults/index.js b/src/SearchResults/index.js index 015e69675..81065f5f1 100644 --- a/src/SearchResults/index.js +++ b/src/SearchResults/index.js @@ -806,7 +806,12 @@ SearchResults.prototype.getFacetValues = function(attribute, opts) { return undefined; } - var options = defaultsPure({}, opts, {sortBy: SearchResults.DEFAULT_SORT}); + var options = defaultsPure({}, opts, { + sortBy: SearchResults.DEFAULT_SORT, + // if no sortBy is given, attempt to sort based on facetOrdering + // if it is given, we still allow to sort via facet ordering first + facetOrdering: !(opts && opts.sortBy) + }); var results = this; var attributes; @@ -818,9 +823,7 @@ SearchResults.prototype.getFacetValues = function(attribute, opts) { } return recSort(function(data, facetName) { - // if no sortBy is given, attempt to sort based on facetOrdering - // if it is given, we still allow to sort via facet ordering first - if (!opts || !opts.sortBy || opts.facetOrdering) { + if (options.facetOrdering) { var facetOrdering = getFacetOrdering(results, facetName); if (Boolean(facetOrdering)) { return sortViaFacetOrdering(data, facetOrdering); @@ -829,7 +832,6 @@ SearchResults.prototype.getFacetValues = function(attribute, opts) { if (Array.isArray(options.sortBy)) { var order = formatSort(options.sortBy, SearchResults.DEFAULT_SORT); - return orderBy(data, order[0], order[1]); } else if (typeof options.sortBy === 'function') { return vanillaSortFn(options.sortBy, data); diff --git a/test/spec/SearchResults/getFacetValues-facetOrdering.js b/test/spec/SearchResults/getFacetValues-facetOrdering.js index 0a5c39656..86b30abdd 100644 --- a/test/spec/SearchResults/getFacetValues-facetOrdering.js +++ b/test/spec/SearchResults/getFacetValues-facetOrdering.js @@ -175,6 +175,38 @@ describe('disjunctive facet', function() { expect(facetValues).toEqual(expected); }); + test('facetOrdering: false without sortBy uses default order', function() { + var data = require('./getFacetValues/disjunctive.json'); + var order = { + renderingContent: { + facetOrdering: { + values: { + brand: { + order: ['Samsung', 'Apple', 'Insignia™'] + } + } + } + } + }; + var results = data.content.results.slice(); + results[0] = Object.assign(order, results[0]); + + var searchParams = new SearchParameters(data.state); + var result = new SearchResults(searchParams, results); + + var facetValues = result.getFacetValues('brand', { + facetOrdering: false + }); + + var expected = [ + {count: 386, isRefined: true, name: 'Apple'}, + {count: 551, isRefined: false, name: 'Insignia™'}, + {count: 511, isRefined: false, name: 'Samsung'} + ]; + + expect(facetValues).toEqual(expected); + }); + test('without facetOrdering, nor sortBy', function() { var data = require('./getFacetValues/disjunctive.json'); var order = { From c1e623f5bf3f74874a43cc55d1ea9ab8e137844f Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Thu, 10 Jun 2021 14:25:22 +0200 Subject: [PATCH 3/5] pinned -> ordered --- src/SearchResults/index.js | 24 +++++++++++-------- .../getFacetValues-facetOrdering.js | 24 +++++++++---------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/SearchResults/index.js b/src/SearchResults/index.js index 81065f5f1..cc5daaf18 100644 --- a/src/SearchResults/index.js +++ b/src/SearchResults/index.js @@ -706,35 +706,39 @@ function vanillaSortFn(order, data) { * @returns {Array} */ function sortViaFacetOrdering(facetValues, facetOrdering) { - var pinnedFacets = []; - var unpinnedFacets = []; + var orderedFacets = []; + var remainingFacets = []; - var pinned = facetOrdering.order || []; - var reversePinned = pinned.reduce(function(acc, name, i) { + var order = facetOrdering.order || []; + /** + * an object with the keys being the values in order, the values their index: + * ['one', 'two'] -> { one: 0, two: 1 } + */ + var reverseOrder = order.reduce(function(acc, name, i) { acc[name] = i; return acc; }, {}); facetValues.forEach(function(item) { - if (reversePinned[item.name] !== undefined) { - pinnedFacets[reversePinned[item.name]] = item; + if (reverseOrder[item.name] !== undefined) { + orderedFacets[reverseOrder[item.name]] = item; } else { - unpinnedFacets.push(item); + remainingFacets.push(item); } }); var sortRemainingBy = facetOrdering.sortRemainingBy; var ordering; if (sortRemainingBy === 'hidden') { - return pinnedFacets; + return orderedFacets; } else if (sortRemainingBy === 'alpha') { ordering = [['name'], ['asc']]; } else { ordering = [['count'], ['desc']]; } - return pinnedFacets.concat( - orderBy(unpinnedFacets, ordering[0], ordering[1]) + return orderedFacets.concat( + orderBy(remainingFacets, ordering[0], ordering[1]) ); } diff --git a/test/spec/SearchResults/getFacetValues-facetOrdering.js b/test/spec/SearchResults/getFacetValues-facetOrdering.js index 86b30abdd..65f863e70 100644 --- a/test/spec/SearchResults/getFacetValues-facetOrdering.js +++ b/test/spec/SearchResults/getFacetValues-facetOrdering.js @@ -6,7 +6,7 @@ var SearchParameters = require('../../../src/SearchParameters'); describe('disjunctive facet', function() { test.each([ [ - 'nothing pinned', + 'nothing ordered', { values: { brand: { @@ -21,7 +21,7 @@ describe('disjunctive facet', function() { ] ], [ - 'all pinned', + 'all ordered', { values: { brand: { @@ -36,7 +36,7 @@ describe('disjunctive facet', function() { ] ], [ - 'one item pinned (implicit sort)', + 'one item ordered (implicit sort)', { values: { brand: { @@ -51,7 +51,7 @@ describe('disjunctive facet', function() { ] ], [ - 'one item pinned (sort by count)', + 'one item ordered (sort by count)', { values: { brand: { @@ -67,7 +67,7 @@ describe('disjunctive facet', function() { ] ], [ - 'one item pinned (sort by alpha)', + 'one item ordered (sort by alpha)', { values: { brand: { @@ -83,7 +83,7 @@ describe('disjunctive facet', function() { ] ], [ - 'one item pinned (sort by hidden)', + 'one item ordered (sort by hidden)', { values: { brand: { @@ -516,7 +516,7 @@ describe('hierarchical facet', function() { expect(facetValues).toEqual(expected); }); - test('root pinned (no sortRemainingBy)', function() { + test('root ordered (no sortRemainingBy)', function() { var data = require('./getRefinements/hierarchical-cards.json'); var order = { renderingContent: { @@ -807,7 +807,7 @@ describe('hierarchical facet', function() { expect(facetValues).toEqual(expected); }); - test('root pinned (sortRemainingBy count)', function() { + test('root ordered (sortRemainingBy count)', function() { var data = require('./getRefinements/hierarchical-cards.json'); var order = { renderingContent: { @@ -1099,7 +1099,7 @@ describe('hierarchical facet', function() { expect(facetValues).toEqual(expected); }); - test('root pinned (sortRemainingBy alpha)', function() { + test('root ordered (sortRemainingBy alpha)', function() { var data = require('./getRefinements/hierarchical-cards.json'); var order = { renderingContent: { @@ -1128,7 +1128,7 @@ describe('hierarchical facet', function() { path: null, exhaustive: true, data: [ - // pinned + // ordered { name: 'Appliances', path: 'Appliances', @@ -1393,7 +1393,7 @@ describe('hierarchical facet', function() { expect(facetValues).toEqual(expected); }); - test('root pinned (sortRemainingBy hidden)', function() { + test('root ordered (sortRemainingBy hidden)', function() { var data = require('./getRefinements/hierarchical-cards.json'); var order = { renderingContent: { @@ -1452,7 +1452,7 @@ describe('hierarchical facet', function() { expect(facetValues).toEqual(expected); }); - test('two levels pinned (sortRemainingBy count)', function() { + test('two levels ordered (sortRemainingBy count)', function() { var data = require('./getRefinements/hierarchical-cards.json'); var order = { renderingContent: { From c4145ee50a7aae7e0f87262d928275b21e1f09ef Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Thu, 10 Jun 2021 14:26:17 +0200 Subject: [PATCH 4/5] better description --- src/SearchResults/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SearchResults/index.js b/src/SearchResults/index.js index cc5daaf18..880b9e2f4 100644 --- a/src/SearchResults/index.js +++ b/src/SearchResults/index.js @@ -743,7 +743,7 @@ function sortViaFacetOrdering(facetValues, facetOrdering) { } /** - * @param {SearchResults} results a results class (this) + * @param {SearchResults} results the search results class * @param {string} attribute the attribute to retrieve ordering of * @returns {FacetOrdering=} */ From af387c60262a3468294294149e1d7af2bc2efeea Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Fri, 11 Jun 2021 17:28:17 +0200 Subject: [PATCH 5/5] simplify tests & code slightly --- src/SearchResults/index.js | 7 +- .../getFacetValues-facetOrdering.js | 957 ++-------------- .../getFacetValues/hierarchical.json | 1010 +++++++++++++++++ 3 files changed, 1099 insertions(+), 875 deletions(-) create mode 100644 test/spec/SearchResults/getFacetValues/hierarchical.json diff --git a/src/SearchResults/index.js b/src/SearchResults/index.js index 880b9e2f4..186338b5d 100644 --- a/src/SearchResults/index.js +++ b/src/SearchResults/index.js @@ -662,7 +662,7 @@ function extractNormalizedFacetValues(results, attribute) { * Sort nodes of a hierarchical or disjunctive facet results * @private * @param {function} sortFn - * @param {HierarchicalFacet|Array} node node to upon which we want to apply the sort + * @param {HierarchicalFacet|Array} node node upon which we want to apply the sort * @param {string[]} names attribute names * @param {number} [level=0] current index in the names array */ @@ -681,8 +681,7 @@ function recSort(sortFn, node, names, level) { return recSort(sortFn, childNode, names, level + 1); }); var sortedChildren = sortFn(children, names[level]); - var newNode = merge({}, node); - newNode.data = sortedChildren; + var newNode = defaultsPure({data: sortedChildren}, node); return newNode; } @@ -768,7 +767,7 @@ function getFacetOrdering(results, attribute) { * might not be respected if you have facet values that are already refined. * @param {string} attribute attribute name * @param {object} opts configuration options. - * @param {boolean} [opts.facetOrdering=false] + * @param {boolean} [opts.facetOrdering] * Force the use of facetOrdering from the result if a sortBy is present. If * sortBy isn't present, facetOrdering will be used automatically. * @param {Array. | function} opts.sortBy diff --git a/test/spec/SearchResults/getFacetValues-facetOrdering.js b/test/spec/SearchResults/getFacetValues-facetOrdering.js index 65f863e70..665c61f22 100644 --- a/test/spec/SearchResults/getFacetValues-facetOrdering.js +++ b/test/spec/SearchResults/getFacetValues-facetOrdering.js @@ -6,7 +6,7 @@ var SearchParameters = require('../../../src/SearchParameters'); describe('disjunctive facet', function() { test.each([ [ - 'nothing ordered', + 'nothing ordered (implicit sort by count)', { values: { brand: { @@ -36,7 +36,7 @@ describe('disjunctive facet', function() { ] ], [ - 'one item ordered (implicit sort)', + 'one item ordered (implicit sort by count)', { values: { brand: { @@ -232,7 +232,7 @@ describe('disjunctive facet', function() { describe('hierarchical facet', function() { test('empty facet ordering', function() { - var data = require('./getRefinements/hierarchical-cards.json'); + var data = require('./getFacetValues/hierarchical.json'); var order = { renderingContent: { facetOrdering: {} @@ -309,206 +309,6 @@ describe('hierarchical facet', function() { isRefined: false, exhaustive: true, data: null - }, - { - name: 'Cameras & Camcorders', - path: 'Cameras & Camcorders', - count: 753, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'TV & Home Theater', - path: 'TV & Home Theater', - count: 617, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Car Electronics & GPS', - path: 'Car Electronics & GPS', - count: 509, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Health, Fitness & Beauty', - path: 'Health, Fitness & Beauty', - count: 385, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Office & School Supplies', - path: 'Office & School Supplies', - count: 302, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Video Games', - path: 'Video Games', - count: 178, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Housewares', - path: 'Housewares', - count: 135, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Office Electronics', - path: 'Office Electronics', - count: 122, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Toys, Games & Drones', - path: 'Toys, Games & Drones', - count: 104, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Connected Home', - path: 'Connected Home', - count: 96, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Telephones & Communication', - path: 'Telephones & Communication', - count: 76, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Wearable Technology', - path: 'Wearable Technology', - count: 68, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Name Brands', - path: 'Name Brands', - count: 55, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Paper', - path: 'Paper', - count: 48, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Musical Instruments', - path: 'Musical Instruments', - count: 40, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Household Essentials', - path: 'Household Essentials', - count: 32, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Scanners, Faxes & Copiers', - path: 'Scanners, Faxes & Copiers', - count: 25, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Office Furniture & Storage', - path: 'Office Furniture & Storage', - count: 14, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Movies & Music', - path: 'Movies & Music', - count: 13, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Magnolia Home Theater', - path: 'Magnolia Home Theater', - count: 10, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Furniture & Decor', - path: 'Furniture & Decor', - count: 6, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Batteries & Power', - path: 'Batteries & Power', - count: 5, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Carfi Instore Only', - path: 'Carfi Instore Only', - count: 4, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Home', - path: 'Home', - count: 1, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Microwaves', - path: 'Microwaves', - count: 1, - isRefined: false, - exhaustive: true, - data: null } ] }; @@ -517,13 +317,13 @@ describe('hierarchical facet', function() { }); test('root ordered (no sortRemainingBy)', function() { - var data = require('./getRefinements/hierarchical-cards.json'); + var data = require('./getFacetValues/hierarchical.json'); var order = { renderingContent: { facetOrdering: { values: { 'hierarchicalCategories.lvl0': { - order: ['Appliances', 'Audio', 'Scanners, Faxes & Copiers'] + order: ['Appliances', 'Best Buy Gift Cards', 'Audio'] } } } @@ -552,118 +352,6 @@ describe('hierarchical facet', function() { exhaustive: true, data: null }, - { - name: 'Audio', - path: 'Audio', - count: 1010, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Scanners, Faxes & Copiers', - path: 'Scanners, Faxes & Copiers', - count: 25, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Cell Phones', - path: 'Cell Phones', - count: 1920, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Computers & Tablets', - path: 'Computers & Tablets', - count: 1858, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Cameras & Camcorders', - path: 'Cameras & Camcorders', - count: 753, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'TV & Home Theater', - path: 'TV & Home Theater', - count: 617, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Car Electronics & GPS', - path: 'Car Electronics & GPS', - count: 509, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Health, Fitness & Beauty', - path: 'Health, Fitness & Beauty', - count: 385, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Office & School Supplies', - path: 'Office & School Supplies', - count: 302, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Video Games', - path: 'Video Games', - count: 178, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Housewares', - path: 'Housewares', - count: 135, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Office Electronics', - path: 'Office Electronics', - count: 122, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Toys, Games & Drones', - path: 'Toys, Games & Drones', - count: 104, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Connected Home', - path: 'Connected Home', - count: 96, - isRefined: false, - exhaustive: true, - data: null - }, { name: 'Best Buy Gift Cards', path: 'Best Buy Gift Cards', @@ -690,116 +378,28 @@ describe('hierarchical facet', function() { ] }, { - name: 'Telephones & Communication', - path: 'Telephones & Communication', - count: 76, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Wearable Technology', - path: 'Wearable Technology', - count: 68, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Name Brands', - path: 'Name Brands', - count: 55, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Paper', - path: 'Paper', - count: 48, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Musical Instruments', - path: 'Musical Instruments', - count: 40, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Household Essentials', - path: 'Household Essentials', - count: 32, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Office Furniture & Storage', - path: 'Office Furniture & Storage', - count: 14, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Movies & Music', - path: 'Movies & Music', - count: 13, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Magnolia Home Theater', - path: 'Magnolia Home Theater', - count: 10, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Furniture & Decor', - path: 'Furniture & Decor', - count: 6, + name: 'Audio', + path: 'Audio', + count: 1010, isRefined: false, exhaustive: true, data: null }, { - name: 'Batteries & Power', - path: 'Batteries & Power', - count: 5, - isRefined: false, + count: 1920, + data: null, exhaustive: true, - data: null - }, - { - name: 'Carfi Instore Only', - path: 'Carfi Instore Only', - count: 4, isRefined: false, - exhaustive: true, - data: null + name: 'Cell Phones', + path: 'Cell Phones' }, { - name: 'Home', - path: 'Home', - count: 1, - isRefined: false, + count: 1858, + data: null, exhaustive: true, - data: null - }, - { - name: 'Microwaves', - path: 'Microwaves', - count: 1, isRefined: false, - exhaustive: true, - data: null + name: 'Computers & Tablets', + path: 'Computers & Tablets' } ] }; @@ -808,150 +408,38 @@ describe('hierarchical facet', function() { }); test('root ordered (sortRemainingBy count)', function() { - var data = require('./getRefinements/hierarchical-cards.json'); + var data = require('./getFacetValues/hierarchical.json'); var order = { renderingContent: { facetOrdering: { values: { 'hierarchicalCategories.lvl0': { - order: ['Appliances', 'Audio', 'Scanners, Faxes & Copiers'], + order: ['Appliances', 'Best Buy Gift Cards'], sortRemainingBy: 'count' } } - } - } - }; - var results = data.content.results.slice(); - results[0] = Object.assign(order, results[0]); - - var searchParams = new SearchParameters(data.state); - var result = new SearchResults(searchParams, results); - - var facetValues = result.getFacetValues('hierarchicalCategories'); - - var expected = { - name: 'hierarchicalCategories', - count: null, - isRefined: true, - path: null, - exhaustive: true, - data: [ - { - name: 'Appliances', - path: 'Appliances', - count: 1533, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Audio', - path: 'Audio', - count: 1010, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Scanners, Faxes & Copiers', - path: 'Scanners, Faxes & Copiers', - count: 25, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Cell Phones', - path: 'Cell Phones', - count: 1920, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Computers & Tablets', - path: 'Computers & Tablets', - count: 1858, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Cameras & Camcorders', - path: 'Cameras & Camcorders', - count: 753, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'TV & Home Theater', - path: 'TV & Home Theater', - count: 617, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Car Electronics & GPS', - path: 'Car Electronics & GPS', - count: 509, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Health, Fitness & Beauty', - path: 'Health, Fitness & Beauty', - count: 385, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Office & School Supplies', - path: 'Office & School Supplies', - count: 302, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Video Games', - path: 'Video Games', - count: 178, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Housewares', - path: 'Housewares', - count: 135, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Office Electronics', - path: 'Office Electronics', - count: 122, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Toys, Games & Drones', - path: 'Toys, Games & Drones', - count: 104, - isRefined: false, - exhaustive: true, - data: null - }, + } + } + }; + var results = data.content.results.slice(); + results[0] = Object.assign(order, results[0]); + + var searchParams = new SearchParameters(data.state); + var result = new SearchResults(searchParams, results); + + var facetValues = result.getFacetValues('hierarchicalCategories'); + + var expected = { + name: 'hierarchicalCategories', + count: null, + isRefined: true, + path: null, + exhaustive: true, + data: [ { - name: 'Connected Home', - path: 'Connected Home', - count: 96, + name: 'Appliances', + path: 'Appliances', + count: 1533, isRefined: false, exhaustive: true, data: null @@ -964,12 +452,12 @@ describe('hierarchical facet', function() { exhaustive: true, data: [ { + name: 'Entertainment Gift Cards', + path: 'Best Buy Gift Cards > Entertainment Gift Cards', count: 17, - data: null, - exhaustive: true, isRefined: true, - name: 'Entertainment Gift Cards', - path: 'Best Buy Gift Cards > Entertainment Gift Cards' + exhaustive: true, + data: null }, { name: 'Swag Gift Cards', @@ -982,113 +470,25 @@ describe('hierarchical facet', function() { ] }, { - name: 'Telephones & Communication', - path: 'Telephones & Communication', - count: 76, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Wearable Technology', - path: 'Wearable Technology', - count: 68, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Name Brands', - path: 'Name Brands', - count: 55, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Paper', - path: 'Paper', - count: 48, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Musical Instruments', - path: 'Musical Instruments', - count: 40, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Household Essentials', - path: 'Household Essentials', - count: 32, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Office Furniture & Storage', - path: 'Office Furniture & Storage', - count: 14, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Movies & Music', - path: 'Movies & Music', - count: 13, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Magnolia Home Theater', - path: 'Magnolia Home Theater', - count: 10, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Furniture & Decor', - path: 'Furniture & Decor', - count: 6, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Batteries & Power', - path: 'Batteries & Power', - count: 5, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Carfi Instore Only', - path: 'Carfi Instore Only', - count: 4, + name: 'Cell Phones', + path: 'Cell Phones', + count: 1920, isRefined: false, exhaustive: true, data: null }, { - name: 'Home', - path: 'Home', - count: 1, + name: 'Computers & Tablets', + path: 'Computers & Tablets', + count: 1858, isRefined: false, exhaustive: true, data: null }, { - name: 'Microwaves', - path: 'Microwaves', - count: 1, + name: 'Audio', + path: 'Audio', + count: 1010, isRefined: false, exhaustive: true, data: null @@ -1100,13 +500,13 @@ describe('hierarchical facet', function() { }); test('root ordered (sortRemainingBy alpha)', function() { - var data = require('./getRefinements/hierarchical-cards.json'); + var data = require('./getFacetValues/hierarchical.json'); var order = { renderingContent: { facetOrdering: { values: { 'hierarchicalCategories.lvl0': { - order: ['Appliances', 'Audio', 'Scanners, Faxes & Copiers'], + order: ['Appliances', 'Best Buy Gift Cards'], sortRemainingBy: 'alpha' } } @@ -1128,7 +528,6 @@ describe('hierarchical facet', function() { path: null, exhaustive: true, data: [ - // ordered { name: 'Appliances', path: 'Appliances', @@ -1137,31 +536,6 @@ describe('hierarchical facet', function() { exhaustive: true, data: null }, - { - name: 'Audio', - path: 'Audio', - count: 1010, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Scanners, Faxes & Copiers', - path: 'Scanners, Faxes & Copiers', - count: 25, - isRefined: false, - exhaustive: true, - data: null - }, - // ordered alphabetically - { - name: 'Batteries & Power', - path: 'Batteries & Power', - count: 5, - isRefined: false, - exhaustive: true, - data: null - }, { name: 'Best Buy Gift Cards', path: 'Best Buy Gift Cards', @@ -1170,12 +544,12 @@ describe('hierarchical facet', function() { exhaustive: true, data: [ { + name: 'Entertainment Gift Cards', + path: 'Best Buy Gift Cards > Entertainment Gift Cards', count: 17, - data: null, - exhaustive: true, isRefined: true, - name: 'Entertainment Gift Cards', - path: 'Best Buy Gift Cards > Entertainment Gift Cards' + exhaustive: true, + data: null }, { name: 'Swag Gift Cards', @@ -1188,25 +562,9 @@ describe('hierarchical facet', function() { ] }, { - name: 'Cameras & Camcorders', - path: 'Cameras & Camcorders', - count: 753, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Car Electronics & GPS', - path: 'Car Electronics & GPS', - count: 509, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Carfi Instore Only', - path: 'Carfi Instore Only', - count: 4, + name: 'Audio', + path: 'Audio', + count: 1010, isRefined: false, exhaustive: true, data: null @@ -1226,166 +584,6 @@ describe('hierarchical facet', function() { isRefined: false, exhaustive: true, data: null - }, - { - name: 'Connected Home', - path: 'Connected Home', - count: 96, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Furniture & Decor', - path: 'Furniture & Decor', - count: 6, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Health, Fitness & Beauty', - path: 'Health, Fitness & Beauty', - count: 385, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Home', - path: 'Home', - count: 1, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Household Essentials', - path: 'Household Essentials', - count: 32, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Housewares', - path: 'Housewares', - count: 135, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Magnolia Home Theater', - path: 'Magnolia Home Theater', - count: 10, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Microwaves', - path: 'Microwaves', - count: 1, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Movies & Music', - path: 'Movies & Music', - count: 13, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Musical Instruments', - path: 'Musical Instruments', - count: 40, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Name Brands', - path: 'Name Brands', - count: 55, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Office & School Supplies', - path: 'Office & School Supplies', - count: 302, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Office Electronics', - path: 'Office Electronics', - count: 122, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Office Furniture & Storage', - path: 'Office Furniture & Storage', - count: 14, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Paper', - path: 'Paper', - count: 48, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'TV & Home Theater', - path: 'TV & Home Theater', - count: 617, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Telephones & Communication', - path: 'Telephones & Communication', - count: 76, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Toys, Games & Drones', - path: 'Toys, Games & Drones', - count: 104, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Video Games', - path: 'Video Games', - count: 178, - isRefined: false, - exhaustive: true, - data: null - }, - { - name: 'Wearable Technology', - path: 'Wearable Technology', - count: 68, - isRefined: false, - exhaustive: true, - data: null } ] }; @@ -1394,13 +592,13 @@ describe('hierarchical facet', function() { }); test('root ordered (sortRemainingBy hidden)', function() { - var data = require('./getRefinements/hierarchical-cards.json'); + var data = require('./getFacetValues/hierarchical.json'); var order = { renderingContent: { facetOrdering: { values: { 'hierarchicalCategories.lvl0': { - order: ['Appliances', 'Audio', 'Scanners, Faxes & Copiers'], + order: ['Appliances', 'Audio', 'Best Buy Gift Cards'], sortRemainingBy: 'hidden' } } @@ -1439,12 +637,29 @@ describe('hierarchical facet', function() { data: null }, { - name: 'Scanners, Faxes & Copiers', - path: 'Scanners, Faxes & Copiers', - count: 25, - isRefined: false, + name: 'Best Buy Gift Cards', + path: 'Best Buy Gift Cards', + count: 80, + isRefined: true, exhaustive: true, - data: null + data: [ + { + name: 'Entertainment Gift Cards', + path: 'Best Buy Gift Cards > Entertainment Gift Cards', + count: 17, + isRefined: true, + exhaustive: true, + data: null + }, + { + name: 'Swag Gift Cards', + path: 'Best Buy Gift Cards > Swag Gift Cards', + count: 20, + isRefined: false, + exhaustive: true, + data: null + } + ] } ] }; @@ -1453,7 +668,7 @@ describe('hierarchical facet', function() { }); test('two levels ordered (sortRemainingBy count)', function() { - var data = require('./getRefinements/hierarchical-cards.json'); + var data = require('./getFacetValues/hierarchical.json'); var order = { renderingContent: { facetOrdering: { diff --git a/test/spec/SearchResults/getFacetValues/hierarchical.json b/test/spec/SearchResults/getFacetValues/hierarchical.json new file mode 100644 index 000000000..805a97bfe --- /dev/null +++ b/test/spec/SearchResults/getFacetValues/hierarchical.json @@ -0,0 +1,1010 @@ +{ + "content": { + "results": [ + { + "hits": [ + { + "name": "3-Year Unlimited Cloud Storage Service Activation Card - Other", + "description": "Enjoy 3 years of unlimited Cloud storage service with this activation card, which allows you to remotely access your favorite music, movies and other media via a compatible device and enables private file sharing with loved ones.", + "brand": "Pogoplug", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Online data backup", + "price": 69, + "price_range": "50 - 100", + "image": "https://cdn-demo.algolia.com/bestbuy/1696302_sc.jpg", + "url": "http://www.bestbuy.com/site/3-year-unlimited-cloud-storage-service-activation-card-other/1696302.p?id=1219066776306&skuId=1696302&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": true, + "popularity": 10000, + "rating": 2, + "objectID": "1696302", + "_highlightResult": { + "name": { + "value": "3-Year Unlimited Cloud Storage Service Activation Card - Other", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Enjoy 3 years of unlimited Cloud storage service with this activation card, which allows you to remotely access your favorite music, movies and other media via a compatible device and enables private file sharing with loved ones.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Pogoplug", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "AMC Theatres - $15 Gift Card - Multi", + "description": "Give the gift of a night out with this AMC Theatres AMC $15 gift card, which is redeemable at AMC Theatres, Cineplex Odeon and other theaters throughout the U.S. for movie tickets and goods at the concession stand.", + "brand": "AMC Theatres", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 15, + "price_range": "1 - 50", + "image": "https://cdn-demo.algolia.com/bestbuy/2592015_sb.jpg", + "url": "http://www.bestbuy.com/site/amc-theatres-15-gift-card-multi/2592015.p?id=1219550857028&skuId=2592015&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 9825, + "rating": 6, + "objectID": "2592015", + "_highlightResult": { + "name": { + "value": "AMC Theatres - $15 Gift Card - Multi", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Give the gift of a night out with this AMC Theatres AMC $15 gift card, which is redeemable at AMC Theatres, Cineplex Odeon and other theaters throughout the U.S. for movie tickets and goods at the concession stand.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "AMC Theatres", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "AMC Theatres - $25 Gift Card", + "description": "This AMC Theatres $25 gift card is redeemable for movie tickets and concessions at AMC Theatres, AMC Loews, AMC Showplace, Cineplex Odeon, Magic Johnson and Star theaters in the U.S.", + "brand": "AMC Theatres", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 25, + "price_range": "1 - 50", + "image": "https://cdn-demo.algolia.com/bestbuy/6643032_sb.jpg", + "url": "http://www.bestbuy.com/site/amc-theatres-25-gift-card/6643032.p?id=1219231132386&skuId=6643032&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 9824, + "rating": 3, + "objectID": "6643032", + "_highlightResult": { + "name": { + "value": "AMC Theatres - $25 Gift Card", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "This AMC Theatres $25 gift card is redeemable for movie tickets and concessions at AMC Theatres, AMC Loews, AMC Showplace, Cineplex Odeon, Magic Johnson and Star theaters in the U.S.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "AMC Theatres", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "Chili's - $10 Gift Card (3-Pack)", + "description": "Treat a group of friends to a delicious meal with this 3-pack of Chili's $10 gift cards that is valid at Chili's Grill & Bar, Romano's Macaroni Grill, On The Border Mexican Grill & Cantina and Maggiano's Little Italy locations in the U.S.", + "brand": "Chili's", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 30, + "price_range": "1 - 50", + "image": "https://cdn-demo.algolia.com/bestbuy/6669016_sb.jpg", + "url": "http://www.bestbuy.com/site/chilis-10-gift-card-3-pack/6669016.p?id=1219236791060&skuId=6669016&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 8062, + "rating": 2, + "objectID": "6669016", + "_highlightResult": { + "name": { + "value": "Chili's - $10 Gift Card (3-Pack)", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Treat a group of friends to a delicious meal with this 3-pack of Chili's $10 gift cards that is valid at Chili's Grill & Bar, Romano's Macaroni Grill, On The Border Mexican Grill & Cantina and Maggiano's Little Italy locations in the U.S.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Chili's", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "Chipotle - $25 Gift Card", + "description": "Treat a loved one to a delicious meal on the go with this Chipotle $25 gift card, which can be redeemed at any Chipotle restaurant in the U.S. for a variety of flavorful menu items prepared with fresh ingredients.", + "brand": "Chipotle", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 25, + "price_range": "1 - 50", + "image": "https://cdn-demo.algolia.com/bestbuy/3267036_sb.jpg", + "url": "http://www.bestbuy.com/site/chipotle-25-gift-card/3267036.p?id=1219575817468&skuId=3267036&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": true, + "popularity": 8060, + "rating": 6, + "objectID": "3267036", + "_highlightResult": { + "name": { + "value": "Chipotle - $25 Gift Card", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Treat a loved one to a delicious meal on the go with this Chipotle $25 gift card, which can be redeemed at any Chipotle restaurant in the U.S. for a variety of flavorful menu items prepared with fresh ingredients.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Chipotle", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "Dairy Queen - $15 Gift Card", + "description": "Compatible with online and mobile apps, this Dairy Queen $15 gift card is accepted nationally at participating Dairy Queen or Orange Julius locations, making it easy to enjoy Dairy Queen cakes, Orange Julius fruit smoothies and other tasty items.", + "brand": "Dairy Queen", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 15, + "price_range": "1 - 50", + "image": "https://cdn-demo.algolia.com/bestbuy/6681207_sb.jpg", + "url": "http://www.bestbuy.com/site/dairy-queen-15-gift-card/6681207.p?id=1219236788879&skuId=6681207&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 7761, + "rating": 3, + "objectID": "6681207", + "_highlightResult": { + "name": { + "value": "Dairy Queen - $15 Gift Card", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Compatible with online and mobile apps, this Dairy Queen $15 gift card is accepted nationally at participating Dairy Queen or Orange Julius locations, making it easy to enjoy Dairy Queen cakes, Orange Julius fruit smoothies and other tasty items.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Dairy Queen", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "Darden Restaurants - $25 Gift Card", + "description": "Present a loved one with a delicious meal at Olive Garden, LongHorn Steakhouse, Bahama Breeze, Seasons 52, Yard House or Red Lobster in the U.S. with this Darden Restaurants $25 gift card, which can be redeemed for appetizers, entrees and more.", + "brand": "Darden Restaurants", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 25, + "price_range": "1 - 50", + "image": "https://cdn-demo.algolia.com/bestbuy/6824125_sb.jpg", + "url": "http://www.bestbuy.com/site/darden-restaurants-25-gift-card/6824125.p?id=1219239884950&skuId=6824125&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 7749, + "rating": 2, + "objectID": "6824125", + "_highlightResult": { + "name": { + "value": "Darden Restaurants - $25 Gift Card", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Present a loved one with a delicious meal at Olive Garden, LongHorn Steakhouse, Bahama Breeze, Seasons 52, Yard House or Red Lobster in the U.S. with this Darden Restaurants $25 gift card, which can be redeemed for appetizers, entrees and more.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Darden Restaurants", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "Darden Restaurants - $60 Gift Card", + "description": "Use this Darden Restaurants $60 gift card at a variety of locations in the U.S., including Olive Garden, LongHorn Steakhouse, Bahama Breeze, Seasons 52, Yard House and Red Lobster restaurants.", + "brand": "Darden Restaurants", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 60, + "price_range": "50 - 100", + "image": "https://cdn-demo.algolia.com/bestbuy/6682206_sb.jpg", + "url": "http://www.bestbuy.com/site/darden-restaurants-60-gift-card/6682206.p?id=1219236788880&skuId=6682206&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 7748, + "rating": 2, + "objectID": "6682206", + "_highlightResult": { + "name": { + "value": "Darden Restaurants - $60 Gift Card", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Use this Darden Restaurants $60 gift card at a variety of locations in the U.S., including Olive Garden, LongHorn Steakhouse, Bahama Breeze, Seasons 52, Yard House and Red Lobster restaurants.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Darden Restaurants", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "eBay - $25 Gift Card", + "description": "Help a loved one celebrate a special occasion with this eBay gift card, which is redeemable for $25 and lets the recipient choose from a great assortment of goods offered by a vast network of online sellers.", + "brand": "eBay", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 25, + "price_range": "1 - 50", + "image": "https://cdn-demo.algolia.com/bestbuy/3904022_sb.jpg", + "url": "http://www.bestbuy.com/site/ebay-25-gift-card/3904022.p?id=1219607581011&skuId=3904022&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 7256, + "rating": 4, + "objectID": "3904022", + "_highlightResult": { + "name": { + "value": "eBay - $25 Gift Card", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Help a loved one celebrate a special occasion with this eBay gift card, which is redeemable for $25 and lets the recipient choose from a great assortment of goods offered by a vast network of online sellers.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "eBay", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "Fandango - $25 Gift Card", + "description": "Provide a friend or relative with tickets to the movies with this Fandango $25 gift card, which can be redeemed via the Fandango Web site and mobile apps to help your loved one avoid waiting on long lines at the theater.", + "brand": "Fandango", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 25, + "price_range": "1 - 50", + "image": "https://cdn-demo.algolia.com/bestbuy/6822172_sb.jpg", + "url": "http://www.bestbuy.com/site/fandango-25-gift-card/6822172.p?id=1219239883569&skuId=6822172&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 6954, + "rating": 3, + "objectID": "6822172", + "_highlightResult": { + "name": { + "value": "Fandango - $25 Gift Card", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Provide a friend or relative with tickets to the movies with this Fandango $25 gift card, which can be redeemed via the Fandango Web site and mobile apps to help your loved one avoid waiting on long lines at the theater.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Fandango", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "Fandango - $45 Gift Card", + "description": "Give a friend or family member the gift of the cinema with this Fandango $45 gift card, which can be redeemed via the Fandango Web site and mobile apps, so your loved one can skip the lines at the box office.", + "brand": "Fandango", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 45, + "price_range": "1 - 50", + "image": "https://cdn-demo.algolia.com/bestbuy/6822205_sb.jpg", + "url": "http://www.bestbuy.com/site/fandango-45-gift-card/6822205.p?id=1219239885213&skuId=6822205&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 6953, + "rating": 6, + "objectID": "6822205", + "_highlightResult": { + "name": { + "value": "Fandango - $45 Gift Card", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Give a friend or family member the gift of the cinema with this Fandango $45 gift card, which can be redeemed via the Fandango Web site and mobile apps, so your loved one can skip the lines at the box office.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Fandango", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "Netflix - $100 Gift Card - Multi", + "description": "This Netflix $100 gift card can be used to redeem TV shows and movies on most Internet-connected devices, so you can treat a friend or relative to entertainment at home or on the go.", + "brand": "Netflix", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 100, + "price_range": "50 - 100", + "image": "https://cdn-demo.algolia.com/bestbuy/3268017_sb.jpg", + "url": "http://www.bestbuy.com/site/netflix-100-gift-card-multi/3268017.p?id=1219575816028&skuId=3268017&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": true, + "popularity": 2812, + "rating": 6, + "objectID": "3268017", + "_highlightResult": { + "name": { + "value": "Netflix - $100 Gift Card - Multi", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "This Netflix $100 gift card can be used to redeem TV shows and movies on most Internet-connected devices, so you can treat a friend or relative to entertainment at home or on the go.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Netflix", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "Netflix - $30 Gift Card", + "description": "Use the Netflix gift card to watch your favorite TV shows and movies on any internet-connected device instantly. Watch as much as you want, whenever you want. It's fast. It's easy. It's a better way to watch.", + "brand": "Netflix", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 30, + "price_range": "1 - 50", + "image": "https://cdn-demo.algolia.com/bestbuy/8090039_sb.jpg", + "url": "http://www.bestbuy.com/site/netflix-30-gift-card/8090039.p?id=1219311894865&skuId=8090039&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 2811, + "rating": 2, + "objectID": "8090039", + "_highlightResult": { + "name": { + "value": "Netflix - $30 Gift Card", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Use the Netflix gift card to watch your favorite TV shows and movies on any internet-connected device instantly. Watch as much as you want, whenever you want. It's fast. It's easy. It's a better way to watch.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Netflix", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "Netflix - $60 Gift Card", + "description": "Use the Netflix gift card to watch your favorite TV shows and movies on any internet-connected device instantly. Watch as much as you want, whenever you want. It's fast. It's easy. It's a better way to watch.", + "brand": "Netflix", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 60, + "price_range": "50 - 100", + "image": "https://cdn-demo.algolia.com/bestbuy/8092019_sb.jpg", + "url": "http://www.bestbuy.com/site/netflix-60-gift-card/8092019.p?id=1219428024107&skuId=8092019&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 2810, + "rating": 5, + "objectID": "8092019", + "_highlightResult": { + "name": { + "value": "Netflix - $60 Gift Card", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Use the Netflix gift card to watch your favorite TV shows and movies on any internet-connected device instantly. Watch as much as you want, whenever you want. It's fast. It's easy. It's a better way to watch.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Netflix", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "Pogoplug - 1-Year Unlimited Cloud Storage Service Activation Card - Multicolor", + "description": "Enjoy 1 year of unlimited Cloud storage service with this activation card, which allows you to remotely access your favorite music, movies and other media via a compatible device and enables private file sharing with loved ones.", + "brand": "Pogoplug", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Online data backup", + "price": 29.99, + "price_range": "1 - 50", + "image": "https://cdn-demo.algolia.com/bestbuy/1696225_sb.jpg", + "url": "http://www.bestbuy.com/site/pogoplug-1-year-unlimited-cloud-storage-service-activation-card-multicolor/1696225.p?id=1219066776119&skuId=1696225&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 1785, + "rating": 1, + "objectID": "1696225", + "_highlightResult": { + "name": { + "value": "Pogoplug - 1-Year Unlimited Cloud Storage Service Activation Card - Multicolor", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Enjoy 1 year of unlimited Cloud storage service with this activation card, which allows you to remotely access your favorite music, movies and other media via a compatible device and enables private file sharing with loved ones.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Pogoplug", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "Pogoplug - 6-Month Unlimited Cloud Storage Service Activation Card - Multicolor", + "description": "Enjoy 6 months of unlimited Cloud storage service with this activation card, which allows you to remotely access your favorite music, movies and other media via a compatible device and enables private file sharing with loved ones.", + "brand": "Pogoplug", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Online data backup", + "price": 14.99, + "price_range": "1 - 50", + "image": "https://cdn-demo.algolia.com/bestbuy/1696087_sb.jpg", + "url": "http://www.bestbuy.com/site/pogoplug-6-month-unlimited-cloud-storage-service-activation-card-multicolor/1696087.p?id=1219066776122&skuId=1696087&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 1784, + "rating": 1, + "objectID": "1696087", + "_highlightResult": { + "name": { + "value": "Pogoplug - 6-Month Unlimited Cloud Storage Service Activation Card - Multicolor", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Enjoy 6 months of unlimited Cloud storage service with this activation card, which allows you to remotely access your favorite music, movies and other media via a compatible device and enables private file sharing with loved ones.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Pogoplug", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + }, + { + "name": "Regal Entertainment Group - $25 Gift Card - Multi", + "description": "Gift the gift of cinematic adventures with this Regal Entertainment Group $25 gift card, which can be redeemed for movie tickets and concessions at Regal Cinemas, Edwards Theatres and United Artists Theatres in the U.S.", + "brand": "Regal Entertainment Group", + "categories": [ + "Best Buy Gift Cards", + "Entertainment Gift Cards" + ], + "hierarchicalCategories": { + "lvl0": "Best Buy Gift Cards", + "lvl1": "Best Buy Gift Cards > Entertainment Gift Cards" + }, + "type": "Misc posa", + "price": 25, + "price_range": "1 - 50", + "image": "https://cdn-demo.algolia.com/bestbuy/6827113_sb.jpg", + "url": "http://www.bestbuy.com/site/regal-entertainment-group-25-gift-card-multi/6827113.p?id=1219239883573&skuId=6827113&cmp=RMX&ky=1uWSHMdQqBeVJB9cXgEke60s5EjfS6M1W", + "free_shipping": false, + "popularity": 1592, + "rating": 4, + "objectID": "6827113", + "_highlightResult": { + "name": { + "value": "Regal Entertainment Group - $25 Gift Card - Multi", + "matchLevel": "none", + "matchedWords": [] + }, + "description": { + "value": "Gift the gift of cinematic adventures with this Regal Entertainment Group $25 gift card, which can be redeemed for movie tickets and concessions at Regal Cinemas, Edwards Theatres and United Artists Theatres in the U.S.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Regal Entertainment Group", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Best Buy Gift Cards", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "Entertainment Gift Cards", + "matchLevel": "none", + "matchedWords": [] + } + ] + } + } + ], + "nbHits": 17, + "page": 0, + "nbPages": 1, + "hitsPerPage": 20, + "processingTimeMS": 1, + "facets": { + "type": { + "Misc posa": 14, + "Online data backup": 3 + }, + "brand": { + "Netflix": 3, + "Pogoplug": 3, + "AMC Theatres": 2, + "Darden Restaurants": 2, + "Fandango": 2, + "Chili's": 1, + "Chipotle": 1, + "Dairy Queen": 1, + "Regal Entertainment Group": 1, + "eBay": 1 + }, + "rating": { + "1": 2, + "2": 5, + "3": 3, + "4": 2, + "5": 1, + "6": 4 + }, + "hierarchicalCategories.lvl0": { + "Best Buy Gift Cards": 17 + }, + "hierarchicalCategories.lvl1": { + "Best Buy Gift Cards > Entertainment Gift Cards": 17 + } + }, + "facets_stats": { + "rating": { + "min": 1, + "max": 6, + "avg": 3, + "sum": 58 + } + }, + "exhaustiveFacetsCount": true, + "query": "", + "params": "query=&page=0&facets=%5B%22brand%22%2C%22type%22%2C%22rating%22%2C%22hierarchicalCategories.lvl0%22%2C%22hierarchicalCategories.lvl1%22%2C%22hierarchicalCategories.lvl2%22%5D&tagFilters=&facetFilters=%5B%5B%22hierarchicalCategories.lvl1%3ABest%20Buy%20Gift%20Cards%20%3E%20Entertainment%20Gift%20Cards%22%5D%5D", + "index": "instant_search" + }, + { + "hits": [ + { + "objectID": "1696302" + } + ], + "nbHits": 80, + "page": 0, + "nbPages": 80, + "hitsPerPage": 1, + "processingTimeMS": 1, + "facets": { + "hierarchicalCategories.lvl0": { + "Best Buy Gift Cards": 80 + }, + "hierarchicalCategories.lvl1": { + "Best Buy Gift Cards > Entertainment Gift Cards": 17, + "Best Buy Gift Cards > Swag Gift Cards": 20 + } + }, + "exhaustiveFacetsCount": true, + "query": "", + "params": "query=&page=0&hitsPerPage=1&attributesToRetrieve=%5B%5D&attributesToHighlight=%5B%5D&attributesToSnippet=%5B%5D&tagFilters=&facets=%5B%22hierarchicalCategories.lvl0%22%2C%22hierarchicalCategories.lvl1%22%5D&facetFilters=%5B%5B%22hierarchicalCategories.lvl0%3ABest%20Buy%20Gift%20Cards%22%5D%5D", + "index": "instant_search" + }, + { + "hits": [ + { + "objectID": "1696302" + } + ], + "nbHits": 10000, + "page": 0, + "nbPages": 1000, + "hitsPerPage": 1, + "processingTimeMS": 1, + "facets": { + "hierarchicalCategories.lvl0": { + "Cell Phones": 1920, + "Computers & Tablets": 1858, + "Appliances": 1533, + "Audio": 1010, + "Best Buy Gift Cards": 80 + } + }, + "exhaustiveFacetsCount": true, + "query": "", + "params": "query=&page=0&hitsPerPage=1&attributesToRetrieve=%5B%5D&attributesToHighlight=%5B%5D&attributesToSnippet=%5B%5D&tagFilters=&facets=%5B%22hierarchicalCategories.lvl0%22%5D", + "index": "instant_search" + } + ] + }, + "state": { + "index": "instant_search", + "query": "", + "facets": [ + "brand" + ], + "disjunctiveFacets": [ + "type", + "rating" + ], + "hierarchicalFacets": [ + { + "name": "hierarchicalCategories", + "attributes": [ + "hierarchicalCategories.lvl0", + "hierarchicalCategories.lvl1", + "hierarchicalCategories.lvl2", + "hierarchicalCategories.lvl3" + ] + } + ], + "facetsRefinements": {}, + "facetsExcludes": {}, + "disjunctiveFacetsRefinements": {}, + "numericRefinements": {}, + "tagRefinements": [], + "hierarchicalFacetsRefinements": { + "hierarchicalCategories": [ + "Best Buy Gift Cards > Entertainment Gift Cards" + ] + }, + "page": 0 + }, + "error": null +}