0

is there a better way to check of empty data in JSON data ?

Here is the type of JSON I have, sometimes data is missing, which is normal :

{
  "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"
}

Here is how I did it :

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);
}

I wonder if there is a way to avoid puting ... == undefined ? null : ... on every line. Maybe a function that would take the item atributes, check if they are undefined and return "null" if undefined or the actual value if not undefined.

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
Polymood
  • 397
  • 3
  • 14
  • 1
    Why are you preferring `null` here? Also what JSON? – evolutionxbox May 03 '22 at 07:49
  • 1
    So you trying to map undefined to null, you can search of how to map object keys... – Dennis Vash May 03 '22 at 07:50
  • 2
    You appear to have a JavaScript Object not JSON – phuzi May 03 '22 at 07:50
  • `"Private info,` <<< is invalid JSON – Roko C. Buljan May 03 '22 at 07:55
  • Why do this in the first place? Are you trying to add all properties that don't exist yet or something? What is the end goal here? –  May 03 '22 at 07:56
  • 2
    There's no need to. If you're OK for `myObject.unknown` being nullish (`undefined`) by default. – Roko C. Buljan May 03 '22 at 07:57
  • Also, just for reference, you can use Object.keys() to get an array of the property names of an object. You don't even need that here though, you just need an array of all keys, then use `item[key]` to dynamically reference all of them. This is essentially a dupe of https://stackoverflow.com/questions/4244896/dynamically-access-object-property-using-variable –  May 03 '22 at 07:59
  • First, if any of the object's properties features an `undefined` value then this object was never retrieved from [valid JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON#javascript_and_json_differences) 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`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries) returns all of an objects own enumerable key-value pairs. – Peter Seliger May 03 '22 at 08:53

4 Answers4

1

From the above comment ...

"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; }

Edit

Since the OP seems to create a somehow more structured data item from kind of a flat/plain data config there are other techniques/tools like 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; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
1

I think what would be most useful is a function that takes an output object specification describing where its elements are to be found in the original structure. It's simple enough to write recursively. This version allows you to specify a property of the input for any location in the output, passing null for those that are missing:

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}

And if we want to restructure an array of such items, it would be just

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

There are two useful extensions we might want to consider:

  • This probably doesn't handle arrays well. We could extend it to do so.

  • We might really want to reformat data from a nested object, not just a flat one. So it might be nice to have entries such as bio: 'additionalInfo.personal.biography', or for the most flexibility, bio: ['additionalInfo', 'personal', 'biography'] so that bio gets the value of the biography property of the value at the personal property of the value at the additionalInfo property in our input object, defaulting again to null.

Neither of these would be difficult. We can leave them as exercises for the reader.

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
0

You could simplify the x == undefined ? null : x parts to x ?? null and wrap it in a function, but you might want to look into a schema validation library like yup.

DustInComp
  • 1,742
  • 8
  • 18
-2

You can also shorthand the check simply with boolean or. For example.

...
var generalData = {
    bio: item.bio || null,
    fullname: item.fullname || null,
    company: item.company || null,
    ...

Expression(x || null) evaluates to null if x is undefined or null. Otherwise it evaluates to x.

Teemu Ikonen
  • 11,861
  • 4
  • 22
  • 35
  • 1
    True, but OP is primarily asking how to avoid hard-coding each property. –  May 03 '22 at 07:55