简体   繁体   中英

Convert JSON to Array of Objects using lodash

I have a JSON object in NoSql database in this format. We are getting this data after migrating some records from some other database and these are multi-valued fields.(Basically we are trying to clean the data for further processing).

{
    "BPContName":"aName;bName;cName",
    "BPContEmail":"aEmail;bEmail;cEmail",
    "BPContPWID":"aPWID;bPWID;cPWID"
}

I want to add another key "bpTableDataName" in the same JSON which should have this format and values,

"bpTableDataName": [
    {
      "name": "aName",
      "email": "aEmail",
      "pwdid": "aPWID"
    },
    {
      "name": "bName",
      "email": "bEmail",
      "pwdid": "bPWID"
    },
    {
      "name": "cName",
      "email": "cEmail",
      "pwdid": "cPWID"
    }
  ],

Is there a way we can achieve this using lodash?

Try following code -

 o = { "BPContName": "aName;bName;cName", "BPContEmail": "aEmail;bEmail;cEmail", "BPContPWID": "aPWID;bPWID;cPWID" } map = { "BPContName" : "name", "BPContEmail": "email", "BPContPWID": "pwdid" } const result = _.reduce(o, (arr, v, k) => ( v.split(";").forEach((x,i) => _.set(arr, `${i}.${map[k]}`, x)), arr ), []) console.log(result)
 <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>

You can use split() to split the values into an array. Then iterate over the array and create the require json and then push that into results.

Check this out.

 var data = { "BPContName":"aName;bName;cName", "BPContEmail":"aEmail;bEmail;cEmail", "BPContPWID":"aPWID;bPWID;cPWID" } var names = data.BPContName.split(';'); var emails = data.BPContEmail.split(';'); var pwids = data.BPContPWID.split(';'); var results = []; for(var i = 0 ; i < names.length; i++) { var obj = { name: names[i], email: emails[i], pwdid: pwids[i] } results.push(obj); } console.log(results)

You could reduce the entries returned by Object.entries like this:

 let obj = { "BPContName": "aName;bName;cName", "BPContEmail": "aEmail;bEmail;cEmail", "BPContPWID": "aPWID;bPWID;cPWID" } let bpTableDataName = Object.entries(obj).reduce((r, [key, value]) => { let splits = value.split(";"); key = key.replace("BPCont", "").toLowerCase(); splits.forEach((split, i) => (r[i] = r[i] || {})[key] = split) return r; }, []) obj.bpTableDataName = bpTableDataName; console.log(obj)

  • Object.entries returns an array of key-value pair. Loop through each of them
  • split the each value at ;
  • get the key by removing BPCont part and making it lowerCase
  • Loop through the splits and update specific keys of objects at each index

Update:

Since you have an extra d in the output's key, you can create a mapping object:

propertyMap = {
  "BPContName": "name",
  "BPContEmail": "email",
  "BPContPWID": "pwdid"
}

And inside the reduce , change the replace code to this:

key = propertyMap[key]

Using Object.assign , Object.entries , Array#map and the spread operator make this trivial

 const inputdata = { "BPContName":"aName;bName;cName", "BPContEmail":"aEmail;bEmail;cEmail", "BPContPWID":"aPWID;bPWID;cPWID" }; const t1=Object.assign({},...Object.entries(inputdata).map(([k,v])=>({[k]:v.split(';')}))); inputdata.bpTableDataName=t1.BPContName.map((name,i)=>({name,email:t1.BPContEmail[i],pwdid:t1.BPContPWID[i]})); console.log(inputdata);

Of course, it wouldn't be me without a one-liner

 const obj = { "BPContName":"aName;bName;cName", "BPContEmail":"aEmail;bEmail;cEmail", "BPContPWID":"aPWID;bPWID;cPWID" }; // one line to rule them all obj.bpTableDataName=Object.entries(obj).reduce((r,[k,v])=>(v.split(';').forEach((v,i)=>(r[i]=r[i]||{})[{BPContName:'name',BPContEmail:'email',BPContPWID:'pwdid'}[k]]=v),r),[]); // console.log(obj);

You can use lodash's _.flow() to create a function. Use _.map() with _.overArgs() to create a function that splits the values, format the key, and then converts them to an array of pairs using _.unzip() , for example [['name', 'x'], ['name', 'y']] . Transpose the array of arrays with _.unzip() to combine pairs of different properties. Then use _.map() to iterate, and convert each array of pairs to an object using _.fromPairs() .

 const { flow, partialRight: pr, map, unzip, overArgs, times, size, constant, split, fromPairs } = _ const keysMap = new Map([['BPContName', 'name'], ['BPContEmail', 'email'], ['BPContPWID', 'pwdid']]) const formatKey = key => keysMap.get(key) const splitVals = pr(split, ';') const fn = flow( pr(map, overArgs( (vals, k) => unzip([vals, times(size(vals), constant(k))]), [splitVals, formatKey]) ), unzip, // transpose pr(map, fromPairs) // convert each pairs array to object ) const data = { "BPContName":"aName;bName;cName", "BPContEmail":"aEmail;bEmail;cEmail", "BPContPWID":"aPWID;bPWID;cPWID" } const results = fn(data) console.log(results)
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

Basically what you need is to zip it.

Snippet:

 let obj = {"BPContName":"aName;bName;cName","BPContEmail":"aEmail;bEmail;cEmail","BPContPWID":"aPWID;bPWID;cPWID"}, res = _.zipWith( ..._.map(obj, v => v.split(';')), (name, email, pwid) => ({name, email, pwid}) ); console.log(res)
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Note, the sequence of the parameters we have to put such a way, the original object give us values when using Object.values or giving us keys when using Object.keys usually it is alphabetical order. But, In case in any env the order is not guranted we can sort it with a sequence of keys as a metadata.

Or else you can explicitly pass the arguments like:

(obj.BPContName.split(';'), obj.BPContEmail.split(';'), obj.BPContPWID.split(';'))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM