Как сделать нормализацию данных РЕКУРСИОННОЙ? - PullRequest
0 голосов
/ 09 июля 2020

Попытка написать служебную функцию, которая нормализует некоторые глубоко вложенные JSON. Мне удалось создать logi c, который анализирует верхние уровни, но у меня проблемы с его рекурсивной работой. Ниже приведен пример данных.

const editorialSpace = {
  sys: {
    type: "Array"
  },
  total: 1,
  skip: 0,
  limit: 100,
  items: [
    {
      sys: {
        space: {
          sys: {
            type: "Link",
            linkType: "Space",
            id: "2kqx4czmzra1"
          }
        },
        id: "5nGEaUoREiCP2zqZTD8euc",
        type: "Entry",
        createdAt: "2020-06-29T16:44:29.447Z",
        updatedAt: "2020-06-29T16:44:29.447Z",
        environment: {
          sys: {
            id: "master",
            type: "Link",
            linkType: "Environment"
          }
        },
        revision: 1,
        contentType: {
          sys: {
            type: "Link",
            linkType: "ContentType",
            id: "contentSlot"
          }
        },
        locale: "en-US"
      },
      fields: {
        name: "Editorial",
        type: "Editorial Index",
        metaContentAsset: {
          sys: {
            type: "Link",
            linkType: "Entry",
            id: "2YgmIPulwrEHha2QMCD7Xr"
          }
        },
        simpleTextContentAssets: [
          {
            sys: {
              type: "Link",
              linkType: "Entry",
              id: "4sdFVqXhJk20OY3j9WMdyU"
            }
          }
        ],
        contentSlots: [
          {
            sys: {
              type: "Link",
              linkType: "Entry",
              id: "4T5NGaHKAOtGUKoxj4Z9x0"
            }
          },
          {
            sys: {
              type: "Link",
              linkType: "Entry",
              id: "2FKoPcIXHNXdbCwDbc83WI"
            }
          }
        ]
      }
    }
  ],
  includes: {
    Entry: [
      {
        sys: {
          space: {
            sys: {
              type: "Link",
              linkType: "Space",
              id: "2kqx4czmzra1"
            }
          },
          id: "1osX6gbbfA30FMrt4urYw6",
          type: "Entry",
          createdAt: "2020-06-29T16:44:29.735Z",
          updatedAt: "2020-06-30T19:31:30.828Z",
          environment: {
            sys: {
              id: "master",
              type: "Link",
              linkType: "Environment"
            }
          },
          revision: 2,
          contentType: {
            sys: {
              type: "Link",
              linkType: "ContentType",
              id: "simpleTextContentAsset"
            }
          },
          locale: "en-US"
        },
        fields: {
          name: "Cool Coats Header",
          desktopText: "Here Are Some Very Cool Coats for Fall"
        }
      },
      {
        sys: {
          space: {
            sys: {
              type: "Link",
              linkType: "Space",
              id: "2kqx4czmzra1"
            }
          },
          id: "2FKoPcIXHNXdbCwDbc83WI",
          type: "Entry",
          createdAt: "2020-06-29T16:44:29.436Z",
          updatedAt: "2020-06-29T16:44:29.436Z",
          environment: {
            sys: {
              id: "master",
              type: "Link",
              linkType: "Environment"
            }
          },
          revision: 1,
          contentType: {
            sys: {
              type: "Link",
              linkType: "ContentType",
              id: "contentSlot"
            }
          },
          locale: "en-US"
        },
        fields: {
          name: "Fall Travel",
          type: "Editorial Story",
          metaContentAsset: {
            sys: {
              type: "Link",
              linkType: "Entry",
              id: "35SVOUtKoIVdsqR7UcBBbY"
            }
          },
          simpleTextContentAssets: [
            {
              sys: {
                type: "Link",
                linkType: "Entry",
                id: "3isf647XwHipHE7J3Uxp2E"
              }
            }
          ]
        }
      },
      {
        sys: {
          space: {
            sys: {
              type: "Link",
              linkType: "Space",
              id: "2kqx4czmzra1"
            }
          },
          id: "2YgmIPulwrEHha2QMCD7Xr",
          type: "Entry",
          createdAt: "2020-06-29T16:44:29.522Z",
          updatedAt: "2020-06-29T16:44:29.522Z",
          environment: {
            sys: {
              id: "master",
              type: "Link",
              linkType: "Environment"
            }
          },
          revision: 1,
          contentType: {
            sys: {
              type: "Link",
              linkType: "ContentType",
              id: "metaContentAsset"
            }
          },
          locale: "en-US"
        },
        fields: {
          title: "Editorial",
          description: "This is a selection of editorial content",
          identifier: "/editorial"
        }
      },
      {
        sys: {
          space: {
            sys: {
              type: "Link",
              linkType: "Space",
              id: "2kqx4czmzra1"
            }
          },
          id: "2kzZZ8NjUUVVZqse14sJE9",
          type: "Entry",
          createdAt: "2020-06-29T16:44:29.838Z",
          updatedAt: "2020-06-29T16:44:29.838Z",
          environment: {
            sys: {
              id: "master",
              type: "Link",
              linkType: "Environment"
            }
          },
          revision: 1,
          contentType: {
            sys: {
              type: "Link",
              linkType: "ContentType",
              id: "metaContentAsset"
            }
          },
          locale: "en-US"
        },
        fields: {
          title: "Cool Coats",
          description: "Cool weather coats by top designers",
          identifier: "/editorials/coolcoats"
        }
      },
      {
        sys: {
          space: {
            sys: {
              type: "Link",
              linkType: "Space",
              id: "2kqx4czmzra1"
            }
          },
          id: "35SVOUtKoIVdsqR7UcBBbY",
          type: "Entry",
          createdAt: "2020-06-29T16:44:29.708Z",
          updatedAt: "2020-06-29T16:44:29.708Z",
          environment: {
            sys: {
              id: "master",
              type: "Link",
              linkType: "Environment"
            }
          },
          revision: 1,
          contentType: {
            sys: {
              type: "Link",
              linkType: "ContentType",
              id: "metaContentAsset"
            }
          },
          locale: "en-US"
        },
        fields: {
          title: "Fall Travel",
          description: "Great destinations for fall",
          identifier: "/editorial/fall-travel"
        }
      },
      {
        sys: {
          space: {
            sys: {
              type: "Link",
              linkType: "Space",
              id: "2kqx4czmzra1"
            }
          },
          id: "3isf647XwHipHE7J3Uxp2E",
          type: "Entry",
          createdAt: "2020-06-29T16:44:29.422Z",
          updatedAt: "2020-06-29T16:44:29.422Z",
          environment: {
            sys: {
              id: "master",
              type: "Link",
              linkType: "Environment"
            }
          },
          revision: 1,
          contentType: {
            sys: {
              type: "Link",
              linkType: "ContentType",
              id: "simpleTextContentAsset"
            }
          },
          locale: "en-US"
        },
        fields: {
          name: "Fall Travel Heading",
          desktopText: "Great Fall Travel Ideas"
        }
      },
      {
        sys: {
          space: {
            sys: {
              type: "Link",
              linkType: "Space",
              id: "2kqx4czmzra1"
            }
          },
          id: "4T5NGaHKAOtGUKoxj4Z9x0",
          type: "Entry",
          createdAt: "2020-06-29T16:44:29.511Z",
          updatedAt: "2020-06-29T16:44:29.511Z",
          environment: {
            sys: {
              id: "master",
              type: "Link",
              linkType: "Environment"
            }
          },
          revision: 1,
          contentType: {
            sys: {
              type: "Link",
              linkType: "ContentType",
              id: "contentSlot"
            }
          },
          locale: "en-US"
        },
        fields: {
          name: "Cool Coats",
          type: "Editorial Story",
          metaContentAsset: {
            sys: {
              type: "Link",
              linkType: "Entry",
              id: "2kzZZ8NjUUVVZqse14sJE9"
            }
          },
          simpleTextContentAssets: [
            {
              sys: {
                type: "Link",
                linkType: "Entry",
                id: "1osX6gbbfA30FMrt4urYw6"
              }
            }
          ]
        }
      },
      {
        sys: {
          space: {
            sys: {
              type: "Link",
              linkType: "Space",
              id: "2kqx4czmzra1"
            }
          },
          id: "4sdFVqXhJk20OY3j9WMdyU",
          type: "Entry",
          createdAt: "2020-06-29T16:44:29.419Z",
          updatedAt: "2020-06-29T16:44:29.419Z",
          environment: {
            sys: {
              id: "master",
              type: "Link",
              linkType: "Environment"
            }
          },
          revision: 1,
          contentType: {
            sys: {
              type: "Link",
              linkType: "ContentType",
              id: "simpleTextContentAsset"
            }
          },
          locale: "en-US"
        },
        fields: {
          name: "Editorial Header",
          desktopText: "Here's some great content"
        }
      }
    ]
  }
};

Вот код, который я написал до сих пор ...

const itemize = fields => {
  for (var key in fields) {
    if (fields.hasOwnProperty(key)) {
      if (typeof fields[key] === "object") {
        if (key === "metaContentAsset") {
          fields[key] = { id: fields[key].sys.id, fields: {} };
        } else {
          const entryIds = fields[key].map(element => element.sys.id);
          fields[key] = [];
          entryIds.forEach(id => fields[key].push({ id: id, fields: {} }));
        }
      }
    }
  }
};

const normalizer = (fields, entries) => {
  for (var key in fields) {
    if (typeof fields[key] === "object" && key !== "contentSlots") {
      if (key === "metaContentAsset") {
        const matchedEntry = entries.find(entry => {
          return entry.sys.id === fields[key].id;
        });
        fields[key].contentType = matchedEntry.sys.contentType.sys.id;
        fields[key].fields = matchedEntry.fields;
      } else {
        fields[key].map(element => {
          const matchedEntry = entries.find(entry => {
            return entry.sys.id === element.id;
          });
          element.contentType = matchedEntry.sys.contentType.sys.id;
          element.fields = matchedEntry.fields;
        });
      }
    }
  }
};

const mapSlots = (slots, entries) => {
  slots.map(slot => {
    const matchedEntry = entries.find(entry => {
      return entry.sys.id === slot.id;
    });
    slot.contentType = matchedEntry.sys.contentType.sys.id;
    slot.fields = matchedEntry.fields;
  });
};

const normalizeJSON = rawObject => {
  const normalObject = {};
  const items = rawObject.items[0];
  normalObject.id = items.sys.id;
  normalObject.contentType = items.sys.contentType.sys.id;
  normalObject.fields = items.fields;
  const fields = normalObject.fields;

  //unpacking of items section from raw json
  itemize(fields);

  //matching nested slots to entries
  const slots = normalObject.fields.contentSlots;
  const entries = rawObject.includes.Entry;
  mapSlots(slots, entries);

  //normalize top level fields
  normalizer(fields, entries);

  return normalObject;
};

normalizeJSON(mockData.editorialSpace);

Любая помощь или направление будут очень благодарны. Я знаю, что мне нужно создать вспомогательную функцию для вызова внутри себя, но не знаю, как и где это сделать. Или, если это возможно, на основе того, что я уже построил. Окончательная форма данных должна напоминать эту.

{
  id: '5nGEaUoREiCP2zqZTD8euc',
  contentType: 'contentSlot',
  fields: {
    name: 'Editorial',
    type: 'Editorial Index',
    metaContentAsset: {
      id: '2YgmIPulwrEHha2QMCD7Xr',
      fields: [Object],
      contentType: 'metaContentAsset'
    },
    simpleTextContentAssets: [ [Object] ],
    contentSlots: [ [Object], [Object] ]
  }
}

Где каждый слот содержимого имеет свойство fields, которое будет содержать дополнительные вложенные слоты. Здесь необходимо применить рекурсию.

Спасибо.

...