Michael Nelles
Michael Nelles

Reputation: 6032

Javascript counting total unique values assigned to the attribute of an object

My database query returns an array of objects like this:

[
    {"id":18,"newStory":"Stormy"},
    {"id":19,"newStory":"Russia"},
    {"id":20,"newStory":"Stormy"},
    {"id":21,"newStory":"Witch Hunt"},
    {"id":22,"newStory":"Stormy"},
    {"id":23,"newStory":"Russia"}
]

I need the total number of stories for each unique newStory. Then, I would like to iterate through these totals, producing something like the following array:

newStoryTotal["Stormy"][2]
newStoryTotal["Witch Hunt"][1]
newStoryTotal["Russia"][3]

I have attempted using reduce and lodash but I lack the expertise. Also I am aware that this can be done using nested DB queries but I am trying to accomplish this with a single query + Javascript doing the count.

Upvotes: 1

Views: 42

Answers (2)

Michael Nelles
Michael Nelles

Reputation: 6032

Further to the above answer I also wanted to turn the array into a 2D array for iteration purposes. I got here standing on shoulders of the code provided by @Kobe . I will post this it could save a future user some time.

https://codepen.io/jsmartio/pen/gObMdvv

<script>
  const data = [
        { id: 18, newsStory: 'Russia' },
        { id: 19, newsStory: 'Stormy' },
        { id: 20, newsStory: 'Russia' },
        { id: 21, newsStory: 'Collision' },
        { id: 22, newsStory: 'Stormy' },
        { id: 23, newsStory: 'James Harden' },
        { id: 24, newsStory: 'Stormy' },
        { id: 25, newsStory: 'Stephen A Smith' },
        { id: 26, newsStory: 'Collision' },
        { id: 27, newsStory: 'Stormy' },
        { id: 28, newsStory: 'Hunter' }
    ]

    const init = () => {

        // this will convert the object in to an array
        var obj = data.reduce((a, {newsStory:s}) => (a[s] = (a[s] || 0) + 1, a), {})
        document.getElementById('res1').innerHTML = '<pre>' + 
                    JSON.stringify(obj).replace(/,/g,",\n") + '</pre>'

        // this will convert at array into a 2d array (see output)
        var countsArr = Object.keys(obj).map(i => { return [String(i), obj[i]]})
        document.getElementById('res2').innerHTML = '<pre>' + 
                    JSON.stringify(countsArr).replace(/],/g,"],\n") + '</pre>'
        console.log(countsArr)

    }

    document.addEventListener('DOMContentLoaded', init);
  </script>

result after @Kobe Code (step 1)

{
"Russia":2,
"Stormy":4,
"Colusion":2,
"James Harden":1,
"Stephen A Smith":1,
"Hunter":1
}

final 2D array after second process

[
   ["Russia",2],
   ["Stormy",4],
   ["Collision",2],
   ["James Harden",1],
   ["Stephen A Smith",1],
   ["Hunter",1]
]

Upvotes: 0

Kobe
Kobe

Reputation: 6456

You can use a simple reduce:

const data = [
  { id: 18, newStory: 'Stormy' },
  { id: 19, newStory: 'Russia' },
  { id: 20, newStory: 'Stormy' },
  { id: 21, newStory: 'Witch Hunt' },
  { id: 22, newStory: 'Stormy' },
  { id: 23, newStory: 'Russia' }
]

const output = data.reduce((a, {newStory:s}) => (a[s] = (a[s] || 0) + 1, a), {})
console.log(output)

Of course, if you are having a hard time reading the one liner, you can always write it out for readability:

const data = [
  { id: 18, newStory: 'Stormy' },
  { id: 19, newStory: 'Russia' },
  { id: 20, newStory: 'Stormy' },
  { id: 21, newStory: 'Witch Hunt' },
  { id: 22, newStory: 'Stormy' },
  { id: 23, newStory: 'Russia' }
]

const output = data.reduce((accumulator, object) => {
  if (accumulator[object.newStory] !== undefined) {
    accumulator[object.newStory]++
  } else {
    accumulator[object.newStory] = 1
  }
  return accumulator
}, {})
console.log(output)

Upvotes: 3

Related Questions