1

I have this facebookResponseObject and i want to flatten the values which are of array type

Right now i'm using a reduce function like this but i was wondering if there's a more cleaner functional way to solve this...

Input Sample

const facebookResponseObject = {
  account_currency: "xxx",
  campaign_name: "xxxxxxxx",
  account_name: "xxxxxxxx",
  adset_name: "xxxxxxxx",
  ad_name: "xxxxxxxx",
  reach: "xxxx",
  impressions: "xxxx",
  frequency: "xxxx",
  spend: "xxxx",
  cpm: "xxxx",
  inline_link_clicks: "xxxx",
  cost_per_inline_link_click: "xxxx",
  inline_link_click_ctr: "xxxx",
  clicks: "xxxx",
  cost_per_unique_click: "xxxx",
  cost_per_action_type: [
    { action_type: "link_click", value: "xxxx" },
    { action_type: "landing_page_view", value: "xxxx" },
    { action_type: "post_engagement", value: "xxxx" },
    { action_type: "page_engagement", value: "xxxx" },
    { action_type: "lead", value: "xxxx" },
    { action_type: "video_view", value: "xxxx" },
    { action_type: "like", value: "xxxx" },
  ],
  actions: [
    { action_type: "link_click", value: "xxxx" },
    { action_type: "landing_page_view", value: "xxxx" },
    { action_type: "post_engagement", value: "xxxx" },
    { action_type: "page_engagement", value: "xxxx" },
    { action_type: "post_reaction", value: "xxxx" },
    { action_type: "lead", value: "xxxx" },
    { action_type: "post", value: "xxxx" },
    { action_type: "comment", value: "xxxx" },
    { action_type: "video_view", value: "xxxx" },
    { action_type: "like", value: "xxxx" },
  ],
  test_key: [
    { action_type: "test1", value: "xxxx" },
    { action_type: "test2", value: "xxxx" },
    { action_type: "test3", value: "xxxx" },
    { action_type: "test4", value: "xxxx" },
  ],
  cpc: "xxxx",
  ctr: "xxxx",
  date_start: "xxxx-xx-xx",
  date_stop: "xxxx-xx-xx",
  account_id: "xxxxxxxx",
};

Transform function

const formatResponse = _.reduce(
  facebookResponseObject,
  (acc, cur, key) => {
    if (_.isArray(cur)) {
      acc = {
        ...acc,
        ..._.chain(cur)
          .keyBy(obj => `${key}.${obj.action_type}`)
          .mapValues(v => v.value)
          .value(),
      };
    } else {
      acc[key] = cur;
    }
    return acc;
  },
  {},
);

Output

{
  account_currency: 'xxx',
  campaign_name: 'xxxxxxxx',
  account_name: 'xxxxxxxx',
  adset_name: 'xxxxxxxx',
  ad_name: 'xxxxxxxx',
  reach: 'xxxx',
  impressions: 'xxxx',
  frequency: 'xxxx',
  spend: 'xxxx',
  cpm: 'xxxx',
  inline_link_clicks: 'xxxx',
  cost_per_inline_link_click: 'xxxx',
  inline_link_click_ctr: 'xxxx',
  clicks: 'xxxx',
  cost_per_unique_click: 'xxxx',
  'cost_per_action_type.link_click': 'xxxx',
  'cost_per_action_type.landing_page_view': 'xxxx',
  'cost_per_action_type.post_engagement': 'xxxx',
  'cost_per_action_type.page_engagement': 'xxxx',
  'cost_per_action_type.lead': 'xxxx',
  'cost_per_action_type.video_view': 'xxxx',
  'cost_per_action_type.like': 'xxxx',
  'actions.link_click': 'xxxx',
  'actions.landing_page_view': 'xxxx',
  'actions.post_engagement': 'xxxx',
  'actions.page_engagement': 'xxxx',
  'actions.post_reaction': 'xxxx',
  'actions.lead': 'xxxx',
  'actions.post': 'xxxx',
  'actions.comment': 'xxxx',
  'actions.video_view': 'xxxx',
  'actions.like': 'xxxx',
  'test_key.test1': 'xxxx',
  'test_key.test2': 'xxxx',
  'test_key.test3': 'xxxx',
  'test_key.test4': 'xxxx',
  cpc: 'xxxx',
  ctr: 'xxxx',
  date_start: 'xxxx-xx-xx',
  date_stop: 'xxxx-xx-xx',
  account_id: 'xxxxxxxx'
}

2 Answers 2

1

You could use flatMap to iterate the object's entries.

  • Don't touch an entry that has a non-array value
  • When there is an array value, iterate over its elements to return new key-value pairs
    • As a key, join the original key with the action_type
    • As a value, take the value property
  • Because we're using flatMap, we ensure we're not returning a nested list.
  • Use Object.fromEntries to transform back in to an object

const flatEntries = (obj) => Object
  .entries(obj)
  .flatMap(
    ([ k, v ]) => Array.isArray(v)
      ? v.map(a => [ `${k}.${a.action_type}`, a.value ] )
      : [[k, v]]
  );

const flattenObject = obj => Object.fromEntries(flatEntries(obj));
  
console.log(flattenObject(facebookResponseObject()));


function facebookResponseObject() { return {
  account_currency: "xxx",
  campaign_name: "xxxxxxxx",
  account_name: "xxxxxxxx",
  adset_name: "xxxxxxxx",
  ad_name: "xxxxxxxx",
  reach: "xxxx",
  impressions: "xxxx",
  frequency: "xxxx",
  spend: "xxxx",
  cpm: "xxxx",
  inline_link_clicks: "xxxx",
  cost_per_inline_link_click: "xxxx",
  inline_link_click_ctr: "xxxx",
  clicks: "xxxx",
  cost_per_unique_click: "xxxx",
  cost_per_action_type: [
    { action_type: "link_click", value: "xxxx" },
    { action_type: "landing_page_view", value: "xxxx" },
    { action_type: "post_engagement", value: "xxxx" },
    { action_type: "page_engagement", value: "xxxx" },
    { action_type: "lead", value: "xxxx" },
    { action_type: "video_view", value: "xxxx" },
    { action_type: "like", value: "xxxx" },
  ],
  actions: [
    { action_type: "link_click", value: "xxxx" },
    { action_type: "landing_page_view", value: "xxxx" },
    { action_type: "post_engagement", value: "xxxx" },
    { action_type: "page_engagement", value: "xxxx" },
    { action_type: "post_reaction", value: "xxxx" },
    { action_type: "lead", value: "xxxx" },
    { action_type: "post", value: "xxxx" },
    { action_type: "comment", value: "xxxx" },
    { action_type: "video_view", value: "xxxx" },
    { action_type: "like", value: "xxxx" },
  ],
  test_key: [
    { action_type: "test1", value: "xxxx" },
    { action_type: "test2", value: "xxxx" },
    { action_type: "test3", value: "xxxx" },
    { action_type: "test4", value: "xxxx" },
  ],
  cpc: "xxxx",
  ctr: "xxxx",
  date_start: "xxxx-xx-xx",
  date_stop: "xxxx-xx-xx",
  account_id: "xxxxxxxx",
}; }

Sign up to request clarification or add additional context in comments.

Comments

1

Thanks for the help @user3297291, i'm gonna use a slightly modified version to your answer (using lodash)

const formatResponse = obj =>
  _.chain(obj)
    .toPairs()
    .flatMap(([key, value]) =>
      _.isArray(value)
        ? _.map(value, actionObj => [`${key}.${actionObj.action_type}`, actionObj.value])
        : [[key, value]],
    )
    .fromPairs()
    .value();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.