0

I am hitting an endpoint that is returning an array of objects, each object can potentially have a set of fields, e.g.,

const FIELDS = [
  'id',
  'title',
  'contributor',
  'mediatype',
  'source'
]

However, some objects will only have some of those fields, some may have all.

const items = [
  {
    "id": 1,
    "title": "some title 1",
    "contributor": "bob",
    "mediatype": "text"
  },
  {
    "id": 2,
    "title": "some title 2",
    "mediatype": "text"
  }.
  {
    "id": 3,
    "title": "some title 3",
    "mediatype": "movies"
    "source": "comcast"
  }
]

I want to "normalize" all the objects such that every single one contains every expected field, filling the "gaps" with null, or some falsey value such that graphql (which I intend to eventually feed it into) is happy.

const items = [
  {
    "id": 1,
    "title": "some title 1",
    "contributor": "bob",
    "mediatype": "text",
    "source": null
  },
  {
    "id": 2,
    "title": "some title 2",
    "mediatype": "text",
    "contributor": null,
    "source": null
  }.
  {
    "id": 3,
    "title": "some title 3",
    "mediatype": "movies",
    "contributor": null,
    "source": "comcast"
  }
]

My "nasty" looking code looks something like this

const normalize = items => 
  items.map(item => {
    FIELDS.forEach(f => {
      if (!item[f]) {
        item[f] = null;
      }
    });
    return item;
  });

Any suggestions for writing this more elegantly - either with vanilla JS or lodash, which I am equally open to using as its already available in my codebase?

jchi2241
  • 2,032
  • 1
  • 25
  • 49

3 Answers3

1

You can use spread syntax, but then it would be better to define FIELDS as a template object:

const FIELDS = {
    id: null,
    title: null,
    contributor: null,
    mediatype: null,
    source: null
};

const normalize = items => items.map(item => ({...FIELDS, ...item}));
trincot
  • 317,000
  • 35
  • 244
  • 286
0

Your if (!item[f]) test will match on any falsy value, which is probably not what you want.

Instead, you should properly check if the key exists, e.g.:

if (!(f in item))

kmoser
  • 8,780
  • 3
  • 24
  • 40
0

Not sure if this is any better really... but here is some equivalent alternative syntax.

Use an "equals itself or null" to squeeze out a bit more sugar:

const normalize = items => 
  items.map(item => {
    FIELDS.forEach(f => item[f] = item[f] || null);
    return item;
  });

Or test everyone's patience with this one liner:

const normalize = items => 
    items.map(item => FIELDS.reduce((acc, field) => {acc[field] = item[field] || null; return acc}, item));

The choice is yours.

Uzer
  • 3,054
  • 1
  • 17
  • 23