Flatten Utility Function

I found myself with a compound results from a GraphQL query that I needed to flatten to a single list. More specifically, I would do a nested query to get all of the ids linked to a higher type going through a few one to many relationships.

The results I retrieved would look something like:

const response = {
  data: {
    queryFoo: [
      {
        bar: {
          baz: [
            { id: "0x1" },
            { id: "0x2" }
          ]
        }
      },
      {
        bar: {
          baz: [
            { id: "0x3" }
          ]
        }
      }
    ]
  }
}

The number of depths are variable and the whether each edge is an object or an array is also variable.

I needed a utility function to take the above variable input and generate the output (if any level is not an object, return it):

[ "0x1","0x2","0x3" ]

I added another use case to this that if at any depth an object has more than a single parameter then it should return the object at that level. This allows me to return something similar to the following if every id attribute has a sibling name attribute (even if the name might be null):

[
  { id: "0x1", name: "first" },
  { id: "0x2", name: "second" },
  { id: "0x3", name: null }
]

And best of all, this function is only 6 lines long (not accounting for a default export) and uses plain vanilla javascript without any additional packages needed. :smiley: Use a compiler to make it compatible with IE.

Javascript:

const flatten = (data) => {
  if (typeof data !== 'object' || data === null) return data
  if (Array.isArray(data)) return data.map((datum) => flatten(datum)).flat(Infinity)
  if (Object.entries(data).length > 1) return data
  return flatten(Object.entries(data)[0][1])
}
4 Likes