5

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.

3
  • seems to me that | 0 is causing the problem. I copied this code from another stackoverflow post. What exactly does the | 0 do? Commented May 16, 2014 at 22:06
  • I should be || not | and it means that if the object to the left of the expression is null return whats to the right, which is 0. Commented May 16, 2014 at 23:03
  • Out of curiosity then - what does just the `` do? Commented May 19, 2014 at 17:15

4 Answers 4

9

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:

Sign up to request clarification or add additional context in comments.

Comments

4

I am the author of the open source project http://www.jinqJs.com. You can easily do that in jinqJs like this:

jinqJs().from(data2).groupBy('date').sum('impressions').select();

Let me know if I can be of anymore help.

Comments

0

You might try to group by date.toString(). Might be safer due to how JS evaluates dates equality

Comments

0

Alternatively, people coming into this question might have zero to a lot of buy in using linq.js.

If you're already pulling it in, go for it, but if this is the first couple real use cases for it, it's worth noting that you can accomplish the same thing in vanilla js:

For this data:

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

You can build an object with properties for each key / person and keep summing the values of those props

var obj = dataArray.reduce((acc, cur) => {
    acc[cur.person] = (acc[cur.person] || 0) + (cur.likes || 0)
    return acc
}, {})

If you want that to be an array of objects, you can convert from an object to array like this

var array = Object.entries(obj).map(entry => {
    return { person: entry[0], likes: entry[1] }
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.