如何用空值一般替换树状对象结构中的每个未定义值?

How to generically replace every undefined value within a tree like object structure with the null value?

是否有更好的方法来检查 JSON 数据中的空数据?

这是我手上的JSON的类型,有时会丢失数据,这是正常的:

{
  "sumRatings": "Private info",
  "phoneNum": "Private info",
  "firstname": "Private info",
  "email": "Private info",
  "fullname": "Private info",
  "talentType": "Private info",
  "ratingCount": "Private info",
  "creationTime": "Private info",
  "lastname": "Private info",
  "currentPosition": "Private info",
  "rgpd": "Private info",
  "bio": "Private info",
  "company": "Private info",
  "whatsapp": "Private info",
  "emptyComs": "Private info",
  "id": "Private info"
}

我是这样做的:

for (const item of allDocs) {
  var generalData = {
    bio: item.bio == undefined ? null : item.bio,
    fullname: item.fullname == undefined ? null : item.fullname,
    company: item.company == undefined ? null : item.company,
    position: item.position == undefined ? null : item.position,
    profilImg: item.profilImg == undefined ? null : item.profilImg,
    talentType: item.talentType == undefined ? null : item.talentType,
    rating: item.rating == undefined ? null : item.rating,
    contacts: {
      gmeets: item.gmeets == undefined ? null : item.gmeets,
      zoom: item.zoom == undefined ? null : item.zoom,
      phone: item.phone == undefined ? null : item.phone,
    },
    skills: item.skills == undefined ? null : item.skills,
    email: item.email == undefined ? null : item.email,
    firstname: item.firstname == undefined ? null : item.firstname,
    lastname: item.lastname == undefined ? null : item.lastname,
    phone: item.phoneNum == undefined ? null : item.phoneNum,
    ratingCount:
      item.ratingCount == undefined ? null : item.ratingCount,
    sumRatings: item.sumRatings == undefined ? null : item.sumRatings,
    currentPosition:
      item.currentPosition == undefined ? null : item.currentPosition,
    creationTime:
      item.creationTime == undefined ? null : item.creationTime,
    rgpd: item.rgpd == undefined ? null : item.rgpd,
    emptyComs: item.emptyComs == undefined ? null : item.emptyComs,
  };
  console.log(generalData);
}

我想知道是否有办法避免在每一行都加上 ... == undefined ? null : ...。 也许一个函数会获取项目属性,检查它们是否未定义,如果未定义则 return “null”,如果未定义则检查实际值。

您也可以 shorthand 简单地使用布尔值或进行检查。例如。

...
var generalData = {
    bio: item.bio || null,
    fullname: item.fullname || null,
    company: item.company || null,
    ...
如果 x 未定义或为空,

表达式(x || null) 的计算结果为空。否则它的计算结果为 x.

您可以将 x == undefined ? null : x 部分简化为 x ?? null 并将其包装在一个函数中,但您可能想要查看模式验证库,例如 yup.

从上面的评论...

"First, if any of the object's properties features an undefined value then this object was never retrieved from valid JSON data since the undefined value is not part of JSON conform encoding. Second, checking all (nested) entries of a tree like structure usually is done by a recursive approach. Third, Object.entries returns all of an objects own enumerable key-value pairs."

function recursivelyNullifyUndefinedValues(obj) {
  Object
    .entries(obj)
    .forEach(([key, value]) => {
      if (!!value && (typeof value === 'object')) {

        recursivelyNullifyUndefinedValues(value);

      } else if (value === undefined) {

        obj[key] = null;
      }
    });
  return obj;
}

const sampleData = {
  talentType: "foo",
  rating: "bar",
  contacts: {
    gmeets: undefined,
    zoom: undefined,
    phone: "baz",
  },
};
console.log('before ...', { sampleData });

console.log('after ...', { returnValue: recursivelyNullifyUndefinedValues(sampleData) });
console.log('after ...', { sampleData });
.as-console-wrapper { min-height: 100%!important; top: 0; }

编辑

由于 OP 似乎从某种 flat/plain 数据配置中创建了某种更结构化的数据项,因此还有其他 techniques/tools,例如 Destructuring assignment / Object destructuring, Destructuring assignment / Default values and Destructuring assignment / Rest syntax

function recursivelyNullifyUndefinedValues(obj) {
  Object
    .entries(obj)
    .forEach(([key, value]) => {
      if (!!value && (typeof value === 'object')) {

        recursivelyNullifyUndefinedValues(value);

      } else if (value === undefined) {

        obj[key] = null;
      }
    });
  return obj;
}

function createNullifiedStructuredDataFromFlatConfig(config) {
  const {
    // handle nullification already
    // via destructuring default values.
    gmeets = null, zoom = null, phone = null, ...rest
  } = config;

  // take care of whatever was left with the `...rest` data.
  return recursivelyNullifyUndefinedValues({
    contacts: {
      gmeets,
      zoom,
      phone,
    },
    ...rest,
  });
}

const flatItemData = {
  talentType: 'foo',
  rating: 'bar',
  gmeets: undefined,
  zoom: undefined,
  phone: 'baz',
  skills: undefined,
  email: 'buzz',
}
const structuredSampleData =
  createNullifiedStructuredDataFromFlatConfig(flatItemData);

console.log({ flatItemData, structuredSampleData });
.as-console-wrapper { min-height: 100%!important; top: 0; }

我认为最有用的是采用输出对象规范的函数,该规范描述了其元素在原始结构中的位置。递归编写很简单。此版本允许您为输出中的任何位置指定输入​​的 属性,为缺少的位置传递 null

const restructure = (spec) => (o) =>
  Object .fromEntries (Object .entries (spec) .map (([k, v]) => [
    k,
    Object (v) === v ? restructure (v) (o) : v in o ? o [v] : null
  ]))


const spec = {
   bio: 'bio',  
   fullname: 'fullname',
   company: 'company',
   position: 'position',
   profilImg: 'item',
   talentType: 'talentType',
   rating: 'rating',
   contacts: {
     gmeets: 'gmeet',
     zoom: 'zoom',
     phone: 'phone',
   },
   skills: 'skills',
   email: 'email',
   firstname: 'firstname',
   lastname: 'lastname',
   phone: 'phoneNum',
   ratingCount: 'ratingCount',
   sumRatings: 'sumRatings',
   currentPosition: 'currentPosition',
   creationTime: 'creationTime',
   rgpd: 'rgpd',
   emptyComs: 'emptyComs',
}


const o = {sumRatings: "Private info", phoneNum: "Private info", firstname: "Private info", email: "Private info", fullname: "Private info", talentType: "Private info", ratingCount: "Private info", creationTime: "Private info", lastname: "Private info", currentPosition: "Private info", rgpd: "Private info", bio: "Private info", company: "Private info", whatsapp: "Private info", emptyComs: "Private info", id: "Private info"}

console .log (restructure (spec) (o))
.as-console-wrapper {max-height: 100% !important; top: 0}

如果我们想重组这样的项目的数组,那就是

const newItems = items .map (restructure (spec))

我们可能要考虑两个有用的扩展:

  • 这可能无法很好地处理数组。我们可以扩展它来这样做。

  • 我们可能真的想重新格式化嵌套对象的数据,而不仅仅是平面对象。因此,拥有诸如 bio: 'additionalInfo.personal.biography' 之类的条目可能会很好,或者为了最大的灵活性,bio: ['additionalInfo', 'personal', 'biography'] 以便 bio 获得 biography 属性 的值输入对象中 additionalInfo 属性 处的值 personal 属性 处的值,再次默认为 null.

这些都不难。我们可以将它们留作 reader.

的练习