linq.js to group by array of objects in javascript

user40721 picture user40721 · May 16, 2014 · Viewed 11k times · Source

I want to use linq.js to group the following data by date.

data2 = [{
    "date": 1399298400.0,
    "adId": 1057946139383,
    "impressions": 1000000
  }, {
    "date": 1399298400.0,
    "adId": 3301784671323,
    "impressions": 535714
  }...... etc.
]; 

Here's my attempt:

var linq = Enumerable.From(data2);
data2 = linq.GroupBy(function (x) {
  return x.date;
}).Select(function (x) {
  return {
    date: x.Key(),
    impressions: x.Sum(function (y) {
      return y.impressions | 0;
    })
  };
}).ToArray();

However, It's not working correctly because the sum of all the impressions before and after the GroupBy are close but not identical.

What is the correct way to use group by in linq.js in this case?

Here's an example in fiddle with full dataset here which alerts the total impressions before and after using the GroupBy.

Answer

KyleMit picture KyleMit · Dec 13, 2014

Solution

You can do this by passing a callback as the third parameter like this:

var grouped = Enumerable.from(dataArray).groupBy("$.person", null, (key, g) => {
  return { 
      person: key, 
      likes: g.sum("$.likes | 0")
 }
}).toArray()

Explanation

In groupBy, the third parameter allows you to modify the results before emitting:

GroupBy > ResultSelector

In JS, the bitwise or operator (a single pipe |) returns the first value if it exists, otherwise it returns the second one. Without it, trying to sum an undefined value with a real one, will return NaN

undefined + 1 // NaN

Without | 0, the result would look like this:

NaN

This example uses shorthand syntax, but if you prefer anytime you see a string with a dollar sign, you can replace it with the lambda syntax like this (they both do the same exact thing):

// Shorthand
.Select("$.impressions")
// Lambda
.Select(function (x) { return x.impressions })

Working demo with Stack Snippets:

var dataArray = [
  {
    person: "james",
    likes: 100
  }, 
  {
    person: "james",
    likes: 250
  }, 
  {
    person: "kyle",
    likes: 300
  }, 
  {
    person: "kyle"
    //,likes: 450
  }
];

var grouped = Enumerable.from(dataArray).groupBy("$.person", null, (key, g) => {
  return { person: key, likes: g.sum("$.likes | 0") }
}).toArray()

console.log(grouped);
<script src="https://unpkg.com/[email protected]/linq.js"></script>

Further Reading: