Group js objects by multiple properties

In the example below I have an array of objects which I group by 2 of their properties (based on https://stackoverflow.com/a/40142591).

        var arr = [{
            "id": 1,
            "tags": "main",
            "yearCode": "2018"
        }, {
            "id": 2,
            "tags": ["main", "blue"],
            "yearCode": "2018"
        }, {
            "id": 3,
            "tags": ["main", "green"],
            "yearCode": "2018"
        }, {
            "id": 25,
            "tags": ["green"],
            "yearCode": "2018"
        }, {
            "id": 26,
            "tags": ["important"],
            "yearCode": "2017"
        }, {
            "id": 29,
            "tags": ["important", "blue"],
            "yearCode": "2017"
        }, {
            "id": 2,
            "tags": ["important", "green"],
            "yearCode": "2017"
        }];


        var mainFilter = "yearCode";
        var secFilter = "tags";
        var result = arr.reduce(function(map, obj) {

          var f1 = map[obj[mainFilter]] = map[obj[mainFilter]] || {};

          var f2 = f1[obj[secFilter]] = f1[obj[secFilter]] || [];

          f2.elements.push(obj);

          return map;
        }, Object.create(null));

        console.log(JSON.stringify(result));



        // NOW
        {
          "2017": {
            "important": [
              {
                "id": 26,
                "tags": ["important"],
                "yearCode": "2017"
              }
            ],
            "important,blue": [
              {
                "id": 29,
                "tags": ["important","blue"],
                "yearCode": "2017"
              }
            ],
            "important,green": [
              {
                "id": 2,
                "tags": ["important","green"],
                "yearCode": "2017"
              }
            ]
          },
          "2018": {
            "main": [
              {
                "id": 1,
                "tags": ["main"],
                "yearCode": "2018"
              }
            ],
            "main,blue": [
              {
                "id": 2,
                "tags": ["main","blue"],
                "yearCode": "2018"
              }
            ],
            "main,green": [
              {
                "id": 3,
                "tags": ["main","green"],
                "yearCode": "2018"
              }
            ],
            "green": [
              {
                "id": 25,
                "tags": ["green"],
                "yearCode": "2018"
              }
            ]
          }
        }

However, I would like the results to be in the following format:

                {
                  "2017": {
                    "important": [
                      {
                        "id": 26,
                        "tags": ["important"],
                        "yearCode": "2017"
                      },
                      {
                        "id": 29,
                        "tags": ["important","blue"],
                        "yearCode": "2017"
                      },
                      {
                        "id": 2,
                        "tags": ["important","green"],
                        "yearCode": "2017"
                      }
                    ],
                    "blue": [
                      {
                        "id": 29,
                        "tags": ["important","blue"],
                        "yearCode": "2017"
                      }
                    ],
                    "green": [
                      {
                        "id": 2,
                        "tags": ["important","green"],
                        "yearCode": "2017"
                      }
                    ]
                  },
                  "2018": {
                    "main": [
                      {
                        "id": 1,
                        "tags": ["main"],
                        "yearCode": "2018"
                      },
                      {
                        "id": 2,
                        "tags": ["main","blue"],
                        "yearCode": "2018"
                      },
                      {
                        "id": 3,
                        "tags": ["main","green"],
                        "yearCode": "2018"
                      }
                    ],
                    "blue": [
                      {
                        "id": 2,
                        "tags": ["main","blue"],
                        "yearCode": "2018"
                      }
                    ],
                    "green": [
                      {
                        "id": 3,
                        "tags": ["main","green"],
                        "yearCode": "2018"
                      },
                       {
                        "id": 25,
                        "tags": ["green"],
                        "yearCode": "2018"
                      }
                    ]
                  }
                }

The groups in the example above include only one of the elements in the array, and each element may be duplicated if needed.

EDIT: I would like the same to happen if “mainFilter” is also an array (for example: if yearCode is [“2018”,”2017”], it will create another group just like if it would be in “secFilter”)

EDIT 2: solved by adding a loop to split the values

Answers:

Answer

Is this what you are looking for ?

var arr = [{
            "id": 1,
            "tags": "main",
            "yearCode": "2018"
        }, {
            "id": 2,
            "tags": ["main", "blue"],
            "yearCode": "2018"
        }, {
            "id": 3,
            "tags": ["main", "green"],
            "yearCode": "2018"
        }, {
            "id": 25,
            "tags": ["green"],
            "yearCode": "2018"
        }, {
            "id": 26,
            "tags": ["important"],
            "yearCode": "2017"
        }, {
            "id": 29,
            "tags": ["important", "blue"],
            "yearCode": "2017"
        }, {
            "id": 2,
            "tags": ["important", "green"],
            "yearCode": "2017"
        }];


        var mainFilter = "yearCode";
        var secFilter = "tags";
        var result = arr.reduce(function(map, obj) 
        {

          var f1 = map[obj[mainFilter]] = map[obj[mainFilter]] || {};

          if(Object.prototype.toString.call(obj[secFilter]) === '[object Array]')
          {
            var idx;
            for(idx in obj[secFilter])
            {
              var f2 = f1[obj[secFilter][idx]] = f1[obj[secFilter][idx]] || [];
              f2.push(obj);             
            }
          }
          else
          {
            var f2 = f1[obj[secFilter]] = f1[obj[secFilter]] || [];
            f2.push(obj);
          }

          return map;
        }, Object.create(null));

        console.log(JSON.stringify(result));

Answer

I believe the below kind of grouping should solve the problem:

var arr=[{id:1,tags:"main",yearCode:"2018"},{id:2,tags:["main","blue"],yearCode:"2018"},{id:3,tags:["main","green"],yearCode:"2018"},{id:25,tags:["green"],yearCode:"2018"},{id:26,tags:["important"],yearCode:"2017"},{id:29,tags:["important","blue"],yearCode:"2017"},{id:2,tags:["important","green"],yearCode:"2017"}];

var mainFilter = "yearCode";
var secFilter = "tags";

var result = arr.reduce((map, obj) => {

    if (!map[obj[mainFilter]]) map[obj[mainFilter]] = {};

    [].concat(obj[secFilter]).forEach(subEl => {

        if (!map[obj[mainFilter]][subEl]) map[obj[mainFilter]][subEl] = [];

        map[obj[mainFilter]][subEl].push(obj);

    });

    return map;

}, {});

console.log(result);

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.