Search code examples
javascriptarraysecmascript-6javascript-objects

What is the most efficient way to merge objects with nested and date keys?


This is an example dataset:

const largeObject = {  
"4249":{  
  "2018-07-25":[  
     {  
        "start":"2016-07-25T14:09:20.453Z",
        "end":"2016-07-25T14:17:52.147Z"
     }
  ]
},
"9939":{  
  "2018-07-25":[  
     {  
        "start":"2016-07-25T00:50:08.768Z",
        "end":"2016-07-25T00:53:16.514Z"
     }
  ]
},
"2149":{  
  "2018-07-25":[  
     {  
        "start":"2016-07-25T00:42:02.569Z",
        "end":"2016-07-25T00:43:07.689Z"
     }
  ]
},
"6929":{  
  "2018-07-24":[  
     {  
        "start":"2016-07-24T00:44:30.479Z",
        "end":"2016-07-24T00:46:41.315Z"
     }
  ]
},
"7930":{  
  "2018-07-24":[  
     {  
        "start":"2016-07-24T00:39:44.152Z",
        "end":"2016-07-24T00:44:05.420Z"
     }
  ]
},
"4796":{  
  "2018-07-22":[  
     {  
        "start":"2016-07-22T12:48:56.169Z",
        "end":"2016-07-22T13:38:28.136Z"
     }
  ]
}
}

I am trying to find the most efficient way to get to something like this:

   const filteredObject = {
 "2018-07-25": [         
     {  
        "start":"2016-07-25T14:09:20.453Z",
        "end":"2016-07-25T14:17:52.147Z"
     },          {  
        "start":"2016-07-25T00:50:08.768Z",
        "end":"2016-07-25T00:53:16.514Z"
     },
     {  
        "start":"2016-07-25T00:42:02.569Z",
        "end":"2016-07-25T00:43:07.689Z"
     }
   ],
"2018-07-24": [         
    {  
        "start":"2016-07-24T00:44:30.479Z",
        "end":"2016-07-24T00:46:41.315Z"
    },
    {  
        "start":"2016-07-24T00:39:44.152Z",
        "end":"2016-07-24T00:44:05.420Z"
    }
  ],
"2018-07-22": [  
     {  
        "start":"2016-07-22T12:48:56.169Z",
        "end":"2016-07-22T13:38:28.136Z"
     }
]    
};

So far, I have done:

const filteredObject = {}
const newArr = []
for(key in largeObject){
  console.log(largeObject[key])  
}

And that gets rid of the random string, but still gets me this:

{ '2018-07-24': 
[ { start: '2016-07-24T00:44:30.479Z',
    end: '2016-07-24T00:46:41.315Z' } ] }
{ '2018-07-25': 
  [ { start: '2016-07-25T00:50:08.768Z',
      end: '2016-07-25T00:53:16.514Z' } ] }
{ '2018-07-25': 
  [ { start: '2016-07-25T14:09:20.453Z',
      end: '2016-07-25T14:17:52.147Z' } ] }
  { '2018-07-24': 
  [ { start: '2016-07-24T00:39:44.152Z',
      end: '2016-07-24T00:44:05.420Z' } ] }
{ '2018-07-22': 
  [ { start: '2016-07-22T12:48:56.169Z',
      end: '2016-07-22T13:38:28.136Z' } ] }
{ '2018-07-25': 
  [ { start: '2016-07-25T00:42:02.569Z',
      end: '2016-07-25T00:43:07.689Z' } ] }

This is far as I've gotten. I still need to find a way to merge all the arrays with the same key values. It seems like I would need to iterate over this object, keep the date as the key, and push all of the arrays associated with that date-key into one array.

What would be the best way to handle something like this? I also want to do this as efficient as possible without having to iterate over the entire large object each time I check for the date-key and/or push the start/end object into an array of it's own.


Solution

  • You can start with Object.values() of your original data. This will give you an array of the values without the first level keys over which you can reduce(). Then for each of those break it into a key and value. Add the key with an array value if it's not already there and merge in the data.

    const largeObject = {  "4249":{  "2018-07-25":[  {  "start":"2016-07-25T14:09:20.453Z","end":"2016-07-25T14:17:52.147Z"}]},"9939":{  "2018-07-25":[  {  "start":"2016-07-25T00:50:08.768Z","end":"2016-07-25T00:53:16.514Z"}]},"2149":{  "2018-07-25":[  {  "start":"2016-07-25T00:42:02.569Z","end":"2016-07-25T00:43:07.689Z"}]},"6929":{  "2018-07-24":[  {  "start":"2016-07-24T00:44:30.479Z","end":"2016-07-24T00:46:41.315Z"}]},"7930":{  "2018-07-24":[  {  "start":"2016-07-24T00:39:44.152Z","end":"2016-07-24T00:44:05.420Z"}]},"4796":{  "2018-07-22":[  {  "start":"2016-07-22T12:48:56.169Z","end":"2016-07-22T13:38:28.136Z"}]}}
        
    let filtered = Object.values(largeObject).reduce((a, c) => {
        Object.entries(c).forEach(([k, v]) => {
            (a[k] || (a[k] = [])).push(...v)
        })
        return a
    },{})
    console.log(filtered)