Home > Blockchain >  serializing an Object by array with splitted name in javascript / jquery
serializing an Object by array with splitted name in javascript / jquery

Time:10-01

i have an array data like this ..

var array = [{name : 'customer.data.profession.code' , value : 'P001'}, 
{name : 'customer.data.profession.name', value : 'DRIVER'}, 
{name : 'customer.data.address', value : '21 Street'},
{name : 'customer.level', value : '1'} ];

i want to serializing that array into single object like below , how can i achieve that ?

let customer = {"data" :  {"profession" : {"code" : "P001", "name" : "DRIVER"} ,
                            "address" : "21 Street"},
                "level" : "1"}

CodePudding user response:

Step 1: Convert each item in your array to self object.

From

{
  name: 'customer.data.profession.code',
  value: 'P001'
}

To

{
    "data": {
      "profession": {
        "code": "P001"
      }
    }
  }

Step 2: Merge all of object to 1 object to get final result by Array.reduce with an deepMerge library.

var array = [{
    name: 'customer.data.profession.code',
    value: 'P001'
  },
  {
    name: 'customer.data.profession.name',
    value: 'DRIVER'
  },
  {
    name: 'customer.data.address',
    value: '21 Street'
  },
  {
    name: 'customer.level',
    value: '1'
  }
];

// Convert each item to object
var tempResult = [];
array.forEach(item => {
  var keys = item.name.replace('customer.', '').split('.').reverse();
  var valueKey = keys.shift();
  var obj = {};
  obj[valueKey] = item.value;
  if (keys.length > 0) {
    obj = keys.reduce((acc, key) => {
      var newObj = {};
      newObj[key] = acc;
      return newObj;
    }, obj)
  }
  tempResult.push(obj);
});

// merge object by reduce
var finalResult = tempResult.reduce((acc, item) => {
  acc = mergeDeep(item, acc)
  return acc
}, {});
console.log(finalResult);

// lib from https://gist.github.com/ahtcx/0cd94e62691f539160b32ecda18af3d6
function mergeDeep(target, source) {
  const isObject = (obj) => obj && typeof obj === 'object';

  if (!isObject(target) || !isObject(source)) {
    return source;
  }

  Object.keys(source).forEach(key => {
    const targetValue = target[key];
    const sourceValue = source[key];

    if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
      target[key] = targetValue.concat(sourceValue);
    } else if (isObject(targetValue) && isObject(sourceValue)) {
      target[key] = mergeDeep(Object.assign({}, targetValue), sourceValue);
    } else {
      target[key] = sourceValue;
    }
  });

  return target;
}

CodePudding user response:

A possible approach could be based on a classic map and reduce task.

In a 1st step one would map the array of { name, value } items into an array where each item features e.g. a keyList property which was computed from the original item name's path value ...

console.log(
  'map result ...',
  [
    { name: 'customer.data.profession.code', value: 'P001' },
    { name: 'customer.data.profession.name', value: 'DRIVER' },
    { name: 'customer.data.address', value: '21 Street' },
    { name: 'customer.level', value: '1' },
  ]
  .map(({ name: keyPath, value }) => ({
    // `.slice(1)` gets rid of the `customer` key.
    keyList: keyPath.split('.').slice(1),
    value,
  }))
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

The 2nd step would process the above array by two nested reduce tasks (the first is processing the altered array, the second does process each altered item's keyList) where one in addition needs to take advantage of object mutation ...

// programmatically builds/aggregates new entries
// by mutating an initially passed reference.
function aggregateReferenceByKeyAndValue({ ref, val }, key, idx, arr) {
  return {
    // - if entry already exists return it ...
    // - ... otherwise initialize and return a new one.
    ref: (ref[key] ??= (idx < (arr.length - 1)) ? {} : val),
    val,
  };
}
const sampleData = [
  { name: 'customer.data.profession.code', value: 'P001' },
  { name: 'customer.data.profession.name', value: 'DRIVER' },
  { name: 'customer.data.address', value: '21 Street' },
  { name: 'customer.level', value: '1' },
];
console.log(
  'map and reduce result ...',
  sampleData
    .map(({ name: keyPath, value }) => ({
      keyList: keyPath.split('.').slice(1),
      value,
    }))
    .reduce((result, { keyList, value }) => {

      // - do not use the reducer's return value,
      // - make use of the `result` mutation instead.
      keyList.reduce(aggregateReferenceByKeyAndValue, {
        ref: result,
        val: value,
      });
      return result;

    }, {}) // the last argument is the to be mutated `result` reference.
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

  • Related