見出し画像

JavaScriptでネストされたオブジェクトをフラットにする関数

今日も元気にノンプロ研でGAS(Google Apps Script)勉強中です。

このnoteは、自分がわからなくなって2度調べたことなどを備忘録的に綴っています。

ネストの深いJSONデータをフラット化したい

Web APIでデータを取得などしているとネストの深いJSONデータが取得されることがしばしばあります。

マスタ項目など一度、スプレッドシートに書き出したい際に、子階層、孫階層のプロパティの値もフラットに取得したいというケースがありました(値がオブジェクトのプロパティは無視したい)。

  const obj = {
    a: 1,
    b: 2,
    c: {
      x: 99,
      y: 98,
      z: {
        aa: 1234,
        bb: 5678
      }
    },
    d: {
      xx: 999,
      yy: 888,
      zz: 777
    }
  };

これを

  const nested = {
    a: 1,
    b: 2,
    x: 99,
    y: 98,
    aa: 1234,
    bb: 5678,
    xx: 999,
    yy: 888,
    zz: 777
  };

こうしたい。

参考にしたのはこちら

そして、自分なりに読み解けた以下のコードを採用しました。

function flatObj(obj) {
  const flattedObj = new Object();
  Object.keys(obj).forEach(key => {
    const value = obj[key];
    if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
      Object.assign(flattedObj, flatObj(value));
    } else {
      flattedObj[key] = value;
    }
  });
  return flattedObj;
};

子階層以下に同じプロパティ名が存在すると値が上書きされてしまう

しかしここでひとつ問題が。

扱いたいAPIから取得されたJSONデータが、いくつかの子階層に同じプロパティ名が存在しており、これを上記の関数でフラット化してしまうと同名のプロパティの値がどちらかに上書き・統合されてしまうことに。

function sampleNestObjFlat() {
  const obj = {
    a: 1,
    b: 2,
    c: {
      x: 99,
      y: 98,
      z: {
        d: 1234,
        e: 5678
      }
    },
    d: {
      x: 999,
      y: 888,
      zz: 777
    }
  };

  console.log(flatObj(obj));
  // { a: 1, b: 2, x: 999, y: 888, d: 1234, e: 5678, zz: 777 }

}

↑ プロパティdやx,yが上書き・統合されています↑

これを親階層のプロパティ名を接頭辞として継承して、あらたにプロパティ名を作成した上で、オブジェクトをフラット化したいと頭悩ませていました。

  const excFlatObj = {
    a: 1,
    b: 2,
    c__x: 99,
    c__y: 98,
    c__z__d: 1234,
    c__z__e: 5678,
    d__x: 999,
    d__y: 888,
    d__zz: 777
  };

こうしたい。

ということで、先程のflatObj()関数をアップデート。

function flatObj(obj, prefix = '') {
  const flattedObj = new Object();
  Object.keys(obj).forEach(key => {
    const value = obj[key];
    if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
      const preKey = prefix + key + '__';
      Object.assign(flattedObj, flatObj(value, preKey));
    } else {
      const newKey = prefix + key;
      flattedObj[newKey] = value;
    }
  });
  return flattedObj;
};

子階層以下のオブジェクトの場合に接頭辞を生成するための第2引数を設定し、親階層の処理時はデフォルト引数をブランクに指定して… とやってうまくいきました。

ノンプロ研オススメです

興味はあったものの、どう学習しはじめればよいのかわからなかったプログラミングでしたが、こうして少しづつ進歩していくのは楽しいですね。

独学では大変なプログラミング学習もノンプロ研に参加するとサクサク進みます。ノンプロ研は参加者みんながフラットなコミュニティで、講師やカリスマなどのヒエラルキーがありません。

それでもお困りごとは、有志の誰かがささっとサポートしてくれる心強いコミュニティです。


この記事が気に入ったらサポートをしてみませんか?