We're thrilled to announce one of the most requested features from the Medusa community - Product Categories! With this new addition to our Product module, you can create, nest, and rank categories and add products to multiple categories.
Our mission is to provide developers with the necessary tools to build rich commerce applications. To build these rich experiences, we need customer facing commerce APIs to be fast, so we’ve optimized Product Categories to deliver on that front. We've also taken the burden of managing complex tree structures that is needed to accomplish this off your hands, and instead provided a simple API for you to work with. This means you can focus on what really matters - creating wonderful experiences for your customers.
Efficient Category Tree Structures
Dealing with tree structures in relational databases is complex. Stores often limit the depth of a menu or category tree because of the performance issues that can stem from having deep tree structures. We didn’t want to enforce nesting limits and focused on building a performant schema that could overcome the limitations of other categorization engines.
We evaluated quite a few different methods on building nested tree structures, built out our criteria, evaluated tradeoffs, circumvented and managed these tradeoffs and concluded with one - Materialized Path. We could write a whole article on this process, but thats for another day.
What we decided to prioritize were these scenarios:
- How quickly can we build an entire tree / sub-tree of categories?
- How quickly can we query products by category?
- How quickly can we query products by a category tree or group of category trees?
We were able to pass these scenarios with great results! We setup an environment with 100 categories that were nested to a depth of 5. With the help of k6.io performance toolkit, we bombarded our server with 400+ requests over 20 second stretches and benchmarked the results. These are the benchmarks for the category API that returns the entire tree of 100 records without caching:
Simple & Performant Tree APIs
After implementing Materialized Path method to model Product Categories, our focus shifted towards designing performant APIs to output this data.
As tree structures, categories differ slightly from regular relational APIs, and this must be considered when building category-related experiences to optimize API queries. Be prepared to dust off your recursive programming skills, because you'll be needing that a bit.
Here are ways you can query the API:
- 1GET /store/product-categories?parent_category_id=null&include_descendants_tree=true
- 1GET /store/product-categories
- 1GET /store/product-categories?q=jeans
- 1GET /store/product-categories/pcat_testid
When querying the retrieve endpoint for product categories, the descendants are always returned. However, for the list endpoint, you must pass in
to explicitly retrieve all descendants of each category. Keep in mind that this operation incurs a cost, as for every record in the collection, we perform an additional query to fetch its descendants. Therefore, it is a good idea to limit the scope to avoid calling it on a potentially large list.
To query products by category, pass category IDs as a parameter to the products API. We have added a pivot table between products and categories to categorize products. When category IDs are provided, we perform a simple join to return the results. For store APIs, we limit categories to only public and active ones.
Like with the categories API, you can include the
parameter to search for not only the category you want but also its descendants. This will result in as many category queries as there are categories to fetch their descendants, but the join on products will remain singular.
Craft Bespoke Experience with Categories
With the complexities of category structures out of the way, you can focus on building rich commerce experiences that delight customers.
Building out deep nested categories without a limit (while keeping performance) is something that most commerce platforms don’t offer. This means that you don’t have to bend to the limitations of the platform on the categorization front. This strengthens our offering for large catalog stores, multi-brand stores, and, generally, stores that need deep and complex categorization. This also future-proofs your store's ability to handle these categorization needs as you scale.
Well-designed category structures can also help customers quickly find the products they're looking for. Categories are another layer of data for upselling and recommendation strategies.
You can unleash your creativity and design unique experiences around categories that set you apart from your competitors or help you achieve your business objectives. We’re excited to see what you build with it.
You can learn more about Product Categories in our documentation.
Share this post