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. 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])
}