Developer forum

Forum » Ecommerce - Standard features » Sorting products

Sorting products

Adrian Ursu Dynamicweb Employee
Adrian Ursu
Reply

Hi guys,
I have a request that seemed pretty simple at first.
I have a structure with 2-3 levels of categories and I need to control the sorting, especially when listing categories with subcategories. Each leaf of the tree stores products of the same type. But when going to the upper level, products will be mixed from multiple categories, meaning multiple types.
I don't have a field on the product defining the type or the priority (yet) and I would like to avoid it if possible. Instead, I would try to use some sorting based on the Parent Group (or primary group) but I have not found an obvious way of doing it.
I see a lot of sort-related generated fields in the index and I am hoping that one of these may help me. 
Any suggestion is very appreciated :)

Thank you,
Adrian


Replies

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Adrian,

 

Ugh... You may have some issues... I assume you have this in your mind (just using 2 group levels for simplicity)

  1. Group A
    1. Subgroup A-A
      1. Product X
    2. Subgroup A-B
      1. Product Y
    3. Subgroup A-C
      1. Product Z
      2. Product W
  2. Group B
    1. Subgroup B-A
    2. Subgroup B-B
    3. Subgroup B-C

 

So using an index builder extender you could do something like

  • Get Group sort order
  • Get Subgroup sort order
  • Get Product sort order
  • Then concat the 3 values - i.e.
    • Product X = 111
    • Product Y = 121
    • Product Z = 131
    • Product W = 132

 

With that in mind:

  • That will get you unique universal sort numbers
  • You need to figure out what to do if a product belong to multiple groups (use the lowest? use the highest?)
  • This assumes you always have 3 levels
  • It would need to be done in an IndexBuilderExtender
  • Beware of performance - you can try to get the concatenated group sort order values first for the entire catalog and store it in a dictionary.

 

Does this help?

Nuno Aguiar

 

 
Adrian Ursu Dynamicweb Employee
Adrian Ursu
Reply

Hi Nuno,
As always, the first one to lend a hand :)

It helps in a way that it clarifies there is no standard way of handling it (I was actually expecting it).
Assignment to multiple groups would present a challenge.
Instead, I will ask the customer to define a limited set of properties for product types and create a scoring for each of them, then store the values on products and create a Group field in the index with the values for each product type.
Hopefully, it will work without adding an index builder extender. If not, we will add an Index Builder extender based on the same logic.

Thank you,
Adrian

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Adrian,

 

Well, I guess Nicolai is always the first :) 

 

But yeah, I could relate as I was asked to solve it in the past. And if there is a standard way, I'm not aware of it.

 

Good luck,

Nuno

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

I do not understand what you want.

But I asked Chatgpt for an example of what you are trying to do - can you confirm? And now you have pointers... :-).

****************

Here’s a simple toy data example (in relational / tabular form) of groups and products illustrating that idea. Use this as a model for how you might store sorts in your index or DB.

Entities & fields

Let me define a few tables / structures:

Groups

GroupID ParentGroupID SortOrder Name
G1 null 10 “Electronics”
G1.1 G1 20 “Mobile Phones”
G1.2 G1 30 “Tablets”
G2 null 40 “Home & Kitchen”
G2.1 G2 50 “Appliances”

Products

ProductID Name (Leaf) GroupID ProductSortOrder UniversalSortKey
P1 “iPhone 15” G1.1 5
P2 “Galaxy S24” G1.1 2
P3 “iPad Pro” G1.2 1
P4 “Blender X2000” G2.1 3
P5 “Toaster 3000” G2.1 1

Compute universal sort key (concatenation approach)

The suggestion is: take the sort value of the top group, of the subgroup (leaf), and of the product itself, combine them into a composite key (e.g. as string or numeric concatenation), so that when you list across groups you have a consistent sort.

Let’s compute:

  • For P1 (“iPhone 15”):

    • Top-level group = G1, SortOrder = 10

    • Leaf group = G1.1, SortOrder = 20

    • Product sort = 5
      → UniversalSortKey = “10|20|05” (or numeric 10_20_05)

  • For P2 (“Galaxy S24”):

    • Group chain: G1 (10) → G1.1 (20), product sort 2
      → UniversalSortKey = “10|20|02”

  • For P3 (“iPad Pro”):

    • G1 (10) → G1.2 (30), product sort 1
      → UniversalSortKey = “10|30|01”

  • For P4 (“Blender X2000”):

    • G2 (40) → G2.1 (50), product sort 3
      → UniversalSortKey = “40|50|03”

  • For P5 (“Toaster 3000”):

    • G2 (40) → G2.1 (50), product sort 1
      → UniversalSortKey = “40|50|01”

So we fill in the UniversalSortKey column:

ProductID Name GroupID ProdSort UniversalSortKey
P1 iPhone 15 G1.1 5 10
P2 Galaxy S24 G1.1 2 10
P3 iPad Pro G1.2 1 10
P4 Blender X2000 G2.1 3 40
P5 Toaster 3000 G2.1 1 40

If you sort by UniversalSortKey (lexicographically or numerically, depending on how you encode), you get:

  1. 10|20|02 → P2 (Galaxy S24)

  2. 10|20|05 → P1 (iPhone 15)

  3. 10|30|01 → P3 (iPad Pro)

  4. 40|50|01 → P5 (Toaster 3000)

  5. 40|50|03 → P4 (Blender X2000)

So the ordering interleaves across categories in a deterministic way based on group priorities.

Notes & caveats (because I’m me, and I question things)

  • If a product belongs to multiple groups, which group do you use to derive the chain? Use the “primary” or “lowest sort value” group, or pick based on some rule.

  • You might need to pad sort order numbers (e.g. make them fixed width: 05, 10, etc.) so that concatenation sorts properly as strings.

  • If your hierarchy levels are inconsistent (some groups depth = 2, others = 3), you need a normalization strategy (fill missing levels with zeros, or default values).

  • Performance: computing this for large catalogs dynamically might be expensive; better to compute ahead and store in the index. (That matches what Nuno warns about) doc.dynamicweb.com

 

I also asked GPT to give me some code:

***********

Dynamicweb already dumps the group sort orders into fields like Sort_GROUP5, Sort_GROUP89, etc. in the index document, along with GroupIDs, ParentGroupIDs, and GroupsTop. That means the data is available in the index pipeline — we just need to stitch it together.

Here’s a working extender example that computes a UniversalSortKey field:

using System;
using System.Linq;
using System.Text;
using Dynamicweb.Ecommerce.Indexing;

namespace Dynamicweb.Indexing.Examples
{
    public class ProductSortKeyExtender : IIndexBuilderExtender<ProductIndexBuilder>
    {
        public void ExtendDocument(IndexDocument indexDocument)
        {
            // GroupIDs is usually a string[] (e.g. "GROUP5 GROUP89 ...")
            var groupIds = indexDocument.ContainsKey("GroupIDs") 
                ? indexDocument["GroupIDs"] as string[] 
                : null;

            if (groupIds == null || groupIds.Length == 0)
                return;

            // Just take the first group for the primary sort (you could implement your own "primary group" logic here)
            var primaryGroupId = groupIds.First();

            // Try to find the group's sort order field (e.g. Sort_GROUP5)
            int groupSort = 0;
            var sortFieldKey = $"Sort_{primaryGroupId}";
            if (indexDocument.ContainsKey(sortFieldKey) && indexDocument[sortFieldKey] is int)
            {
                groupSort = (int)indexDocument[sortFieldKey];
            }

            // Product sort order (stored as Sort_GROUPX per group, so we fallback to groupSort or 0 if missing)
            // If you have a product-level sort field independent of groups, swap this in
            int productSort = groupSort; 

            // Optionally: also bring in top-level group order if available
            int topGroupSort = 0;
            var topGroups = indexDocument.ContainsKey("GroupsTop") 
                ? indexDocument["GroupsTop"] as string[] 
                : null;

            if (topGroups != null && topGroups.Any())
            {
                var topGroupId = topGroups.First();
                var topSortFieldKey = $"Sort_{topGroupId}";
                if (indexDocument.ContainsKey(topSortFieldKey) && indexDocument[topSortFieldKey] is int)
                {
                    topGroupSort = (int)indexDocument[topSortFieldKey];
                }
            }

            // Build the universal sort key, padded for lexicographic sorting
            string universalSortKey = $"{topGroupSort:D3}|{groupSort:D3}|{productSort:D3}";

            // Add it to the document
            if (!indexDocument.ContainsKey("UniversalSortKey"))
            {
                indexDocument.Add("UniversalSortKey", universalSortKey);
            }
            else
            {
                indexDocument["UniversalSortKey"] = universalSortKey;
            }
        }
    }
}

 

How it works

  • Finds the group IDs from the GroupIDs array.

  • Pulls the group sort order from the corresponding Sort_GROUPxxx fields.

  • Optionally includes top group sort order (from GroupsTop if available).

  • Builds a padded key like 010|020|005 so lexicographic sorting works.

  • Writes it into the index as UniversalSortKey.

Example result

For a product in GROUP5 (sort=20), under top group GROUP1 (sort=10), with product sort=5, the extender will add:

UniversalSortKey = "010|020|005" 

You can now sort on this field across products consistently in queries.

 

Hope this helps.

 
Adrian Ursu Dynamicweb Employee
Adrian Ursu
Reply

Hi Nicolai,
I believe this is a very good approach, but it may be too complicated for my use case. I have simplified it based on a Group field and a property on the product, and it seems to work.
Of course, things may change as the number of product types and rules will change.
The example is very good and I will keep it for future needs.
Thank you very much,
Adrian

 

You must be logged in to post in the forum