Atlas Search to return all the applicable filters for a given search query without specifying

So, We are building a Full Text Search and Filtering option for a Furniture market place. Given a search query we can have over 100 products which are returned, Is there a way we can extract all the filters which can be applied on the results without specifying them in the aggregation pipeline.

For Example:
If I am searching for product by the name bed, I want the result to return all the beds along with all the facets which can be applied on the bed, like the Sizes, Colours, Material etc without specifying these facets before hand.

One trick for this is a two pass query technique. First, adjust your documents to contain another field, say facet_attributes. This field will be an array of strings, each value representing the attributes for that particular product. A couch would have facet_attributes=["Size", Colour", "Material"] whereas a table document would have facet_attributes=["Length", "Width", "Height", "Material", "Colour"] and so on where you’d have facet fields on each document with those respective attributes.

An initial query, which could only be for facets via $searchMeta, would facet on the field facet_attributes for a given query. The facet values returned will give you the attributes represented in the subset of matching products. Using those returned values, issue a second query ($search this time) using the desired attributes returned from the first query.

2 Likes

Let’s say I update my document to have a facet_attributes=[“Size”,“Colour”…], Now I want to fetch all the possible filter options with their values. For example Colour : Grey, Blue, Purple etc… and so on for every fields, How Can I accomplish this using the $searchMeta stage

My Current structure is like this

{
  "pricing": {
    "discount": {
      "value": 990,
      "displayValue": "₹ 990"
    },
    "discountPercent": {
      "value": 0.23,
      "displayValue": "-23%"
    },
    "strikePrice": {
      "value": 4289,
      "displayValue": "₹ 4,289"
    },
    "basePrice": {
      "value": 3299,
      "displayValue": "₹ 3,299"
    }
  },
  "filters": {
    "collectionFilters": [
      {
        "collectionName": "living_room_buy",
        "collectionLabel": "Living Room",
        "collectionType": "CATEGORY_BUY",
        "collectionRank": 26
      }
    ],
    "attributeFilters": [
      {
        "attributeName": "primary_material",
        "attributeLabel": "Primary Material",
        "attributeValue": "Engineered Wood",
        "attributeRank": 3
      },
      {
        "attributeName": "finish",
        "attributeLabel": "Finish",
        "attributeValue": "Slate Grey",
        "attributeRank": 4
      },
      {
        "attributeName": "config_type",
        "attributeLabel": "Config type",
        "attributeValue": "Side Unit",
        "attributeRank": 7
      }
    ],
    "subCollectionFilters": [
      {
        "collectionName": "chest_of_drawers_buy",
        "collectionLabel": "Chest of Drawers",
        "collectionType": "CATEGORY_BUY",
        "collectionRank": 34
      }
    ]
  }
}

I think you’ll need to restructure your document layout such that each attribute/value has its own field name, such as Colour and Size. At that point you can do an initial query with faceting on the facet_attributes field to get the attributes in a result set, and then make another request to facet on all of those attributes and get their unique values. As it is, each of your attribute values are in an attributeValue field that can’t be distinguished from any other attribute.

I could either restructure the documents like how you have laid it out , Which would look like this

"filters" : [
    {
        "primary_material" : {
            "value" : "Engineered Wood",
        }, 
        "finish" : {
            "value" : "Slate Grey",
        },
        "config_type" : {
            "value" : "Side Unit",
        },
        "collection" : {
            "value" : "living_room_buy",
        },
        "sub_collection" : {
            "value" : "chest_of_drawers_buy",
        }
        
    }
]

Or I can just use a mongo pipeline which does things like group, unwind, addToSet

Is there any significant advantage if I use the `searchMeta or can i just do it the native mongo way? Will there be a huge performance impact?

I am thinking I will run two queries on runtime simultaneously , The first one will be searching for all the products and returning them and will only have the $search stage.
The second query which will run parallely, It will first perform a $search and then I will only project out the filters field and pass it to a mongo pipeline which will perform the group, unwind and addToSet etc to extract all the available filters.
Is there a better approach for this?

Also, I am a M20 Dedicated customer, Is there a way I can get better support?