Mina Fawzy
Mina Fawzy

Reputation: 21452

typescript - multi level groupby with function on a property

I have a table in my database contain templates, that template consist of some fields like Carrier, Category

I need to group them by Carrier and under each Carrier I would like to group them by Category

here is my code where formatted is the code that comes from the database here is a sample of formatted

[{carrier:'carier1',category:'category1',name:'Value1' , ....}, {carrier:'carier1',category:'category1',name:'Value2'}, {carrier:'carier1',category:'category1',name:'Value3'}, {carrier:'carier1',category:'category2',name:'Value4'}, {carrier:'carier2',category:'category1',name:'Value5'}, {carrier:'carier2',category:'category1',name:'Value6'}];

here is my code

export interface TemplateList {
  carrier?: string;
  categories?: templateCategory[];
}
export interface templateCategory {
  category?: string;
  templates?: {};
}

import R from "ramda";
var templateList: TemplateList[] = [];
    const byCarrier = R.groupBy((element: any) => {
      return element.carrier;
    });
    const byCategory = R.groupBy((element: any) => {
      return element.category;
    });

    var carriers = byCarrier(formatted);
    Object.keys(carriers).forEach((element) => {
      var item: TemplateList = {};
      item.carrier = element;
      var categories = byCategory(carriers[element]);
      var templatelist: templateCategory[] = [];
      Object.keys(categories).forEach((cat) => {
        var templateCat: templateCategory = {};
        templateCat.category = cat;
        templateCat.templates = categories[cat];
        templatelist.push(templateCat);
      });
      item.categories = templatelist;
      templateList.push(item);
    });
    return { carriers: templateList };

enter image description here

expected data format

{"carriers": [
                {
                    "carrier": "carrier1",
                    "categories": [
                        {
                            "category": "Misc",
                            "templates": [
                                {
                                    "name": "name1",
                                    "category": "Misc",
                                    "carrier": "carrier1",
                                    "body": "body1",
                                    "subject": "subject",
                                    "ticketResponseTemplateId": 235
                                }
                            ]
                        }
                    ]
                },
                {
                    "carrier": "carrier2",
                    "categories": [
                        {
                            "category": "Misc",
                            "templates": [
                                {
                                    "name": "Aetna MS - Add State",
                                    "category": "Misc",
                                    "carrier": "carrier2",
                                    "body": "<p>new body</p>",
                                    "subject": "Aetna MS - Adding a State",
                                    "ticketResponseTemplateId": 234
                                }
                            ]
                        }
                    ]
                }
            ]
        }

Upvotes: 0

Views: 361

Answers (2)

h0ss
h0ss

Reputation: 643

I wrote a general function that you can apply to any level of group nesting you need and that would yield you the appropriate types, the function is the following

function groupBy<T, E>(array: T[], key: string, map: (group: T[], key: string) => E) {
  const groups = array.reduce((acc, current) => {
    (acc[current[key]] = acc[current[key]] || []).push(current);
    return acc;
  }, {});

  return Object.keys(groups).map((group) => {
    return map(groups[group], group);
  })
}

For your example, you can use like this :


const grouped = groupBy<any, TemplateList>(response, 'carrier', (carrierList, carrier) => {
    return {
      carrier,
      categories: groupBy<any, TemplateCategory>(carrierList, 'category', (categoryList, category) => {
        return {
          category,
          templates: categoryList.map((v) => {
            return {
              name: v.name,
              /* Any other projection in the final object */
            };
          })
        };
      })
    }
})

Here is a working Stackblitz https://stackblitz.com/edit/typescript-defxxj

Upvotes: 1

Mahmoud Nasr
Mahmoud Nasr

Reputation: 642

check this, I tried to figure out the database query return

export interface TemplateList {
    carrier?: string;
    categories?: templateCategory[];
}
export interface templateCategory {
    category?: string;
    templates?: {};
}



var templateList: TemplateList[] = [];
var carriers = [{ carier: 'carier1', category: 'category1', template: 't1' },
{ carier: 'carier1', category: 'category1', template: 't2' },
{ carier: 'carier1', category: 'category1', template: 't3' },
{ carier: 'carier1', category: 'category2', template: 't4' },
{ carier: 'carier2', category: 'category1', template: 't5' },
{ carier: 'carier2', category: 'category1', template: 't6' }];
carriers.forEach((carier) => {
    if (templateList?.length > 0) {
        templateList.forEach(tempItem => {
            if (tempItem.carrier == carier.carier) {
                const tempCat: templateCategory = { category: carier.category, templates: carier.template };
                tempItem.categories.push(tempCat);
            }
            else {
                const tempCat: templateCategory = { category: carier.category, templates: carier.template };
                templateList.push({ carrier: carier.carier, categories: [tempCat] })
            }
        }

        );
    } else {
        const tempCat: templateCategory = { category: carier.category, templates: carier.template };
        templateList.push({ carrier: carier.carier, categories: [tempCat] })
    }
});
console.log({ carriers: templateList });

Upvotes: 1

Related Questions