Kirti Jha
Kirti Jha

Reputation: 123

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?

Upvotes: 3

Views: 2997

Answers (6)

Ori Drori
Ori Drori

Reputation: 193047

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>

Upvotes: 0

Koushik Chatterjee
Koushik Chatterjee

Reputation: 4175

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(';'))

Upvotes: 0

Jaromanda X
Jaromanda X

Reputation: 1

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

Upvotes: 0

Yasser Hussain
Yasser Hussain

Reputation: 854

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/[email protected]/lodash.min.js"></script>

Upvotes: 1

adiga
adiga

Reputation: 35261

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]

Upvotes: 0

Ishwar Patil
Ishwar Patil

Reputation: 1736

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)

Upvotes: 0

Related Questions