Search code examples
javascriptobjectmeteorhandlebars.jsspacebars

Meteor remove duplicate property in an array of objects


I can't seem to figure out how to merge the two Video bullet points into one bullet point that contains the two drivers.

Collection Data

"drivers":[
    {"title":"Nvidia Video Driver","category":"Video","version":"331.82","description":"Lorem ipsum dolor sit amet","filename":"nvidia.exe"},
    {"title":"Intel Video Driver","category":"Video","version":"10.4.4740","description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse ultricies.","filename":"intel.exe"},
    {"title":"Realtek Audio","category":"Audio","version":"1.25.21","description":"consectetur adipiscing elit. Suspendisse ultricies.","filename":"audio.exe"},
    {"title":"Storage controller","category":"chipset","version":"23.13.412","description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit.","filename":"chip.exe"}
  ]

deviceDetails.helpers

Template.deviceDetails.helpers({
deviceDrivers:function(drivers) {

    var driverArray = drivers.sort(function(a, b) {
        if (a.category.toLowerCase() < b.category.toLowerCase()) return -1;
        if (a.category.toLowerCase() > b.category.toLowerCase()) return 1;
        return 0;
      });

    console.log(driverArray);
    return driverArray;
}
});

DeviceDetails.html

<ul>
    {{#each deviceDrivers device.drivers}}
        <li class="text-capitalize list-unstyled">{{category}}<ul>
          <li><a href="{{filename}}">{{title}} -> {{version}}</a><br>
            {{description}}
          </li></ul>
        </li>
    {{/each}}
</ul>

Result

- Audio
 - Realtek Audio -> 1.25.21
     - Consectetur Adipiscing Elit. Suspendisse Ultricies.
- Chipset
 - Storage Controller -> 23.13.412
     - Lorem Ipsum Dolor Sit Amet, Consectetur Adipiscing Elit.
- Video
    - Nvidia Video Driver -> 331.82
      - Lorem Ipsum Dolor Sit Amet
- Video (!REMOVE! line)
    - Intel Video Driver -> 10.4.4740
      - Lorem Ipsum Dolor Sit Amet, Consectetur Adipiscing Elit. Suspendisse Ultricies.

Desired Result

- Audio
 - Realtek Audio -> 1.25.21
     - Consectetur Adipiscing Elit. Suspendisse Ultricies.
- Chipset
 - Storage Controller -> 23.13.412
     - Lorem Ipsum Dolor Sit Amet, Consectetur Adipiscing Elit.
- Video
    - Nvidia Video Driver -> 331.82
      - Lorem Ipsum Dolor Sit Amet
    - Intel Video Driver -> 10.4.4740
      - Lorem Ipsum Dolor Sit Amet, Consectetur Adipiscing Elit. Suspendisse Ultricies.

Update

I was able to get the desired result using Julien Answer.

deviceDrivers:function(drivers) {

    var driverArray = drivers.reduce(function(result, driver){
        var category = result.find(function(search){
            return search.category === driver.category;
        });
        if(category){
            category.drivers.push(driver);
        } else {
            result.push({
                category:driver.category,
                drivers: [driver]
            });
        }
            return result
        },[]).sort(function(a, b) {
    if (a.category.toLowerCase() < b.category.toLowerCase()) return -1;
    if (a.category.toLowerCase() > b.category.toLowerCase()) return 1;
    return 0;
  });

    console.log(driverArray);
    return driverArray;
}

Update 2

Christian Fritz Answer worked perfectly after his edit.

deviceDrivers:function(drivers) {
    var test = _.map(
    _.sortBy(
        _.groupBy(drivers, 'category'), function(value, key) {
            return key.toLowerCase();
        }), function(value, key) {
            return {category:value[0].category,drivers: value};
        });
    console.log(test);
    return test;
}

Solution

  • I would suggest pre-grouping:

    JS:

    Template.deviceDetails.helpers({
        deviceDrivers:function(drivers) {
    
            var driverGroups = 
                _.map(
                    _.sortBy(
                        _.groupBy(drivers, 'category'), function(value, key) {
                            return key.toLower();
                        }), function(value, key) {
                            return {key: key, value: value};
                        });
    
            console.log(driverGroups);
            return driverGroups;
        }
    });
    

    HTML:

    <ul>
        {{#each deviceDrivers device.drivers}}
            <li class="text-capitalize list-unstyled">{{key}}<ul>
              {{#with value}}
              <li><a href="{{filename}}">{{title}} -> {{version}}</a><br>
                {{description}}
              </li></ul>
              {{/with}}
            </li>
        {{/each}}
    </ul>