Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript: How to map two objects to get the output which map the Id of first object to the name of other object?

I am trying to make a function that maps the data2 object value to the name of the data1.

I tried to iterate data2 object2 with data1 but it is not working properly. I am able to map them but not getting the value of data1 when it is not there in data2.

Is there any way I can map properly to get the desired output mentioned in the code?

let data1 = {
    attributes: [{
            Id: 'test1',
            Name: 'Test1',
            Type: 'date'
        },
        {
            Id: 'test2',
            Name: 'Test2',
            Type: 'string'
        },
        {
            Id: 'test3',
            Name: 'Test3',
            Type: 'string'
        },
        {
            Id: 'test4',
            Name: 'Test4',
            Type: 'boolean'
        }
    ]
};

let data2 = {
    value: [{
            test1: '10-12-2021',
            test2: '4',
            dummy: 'ignore me'
        },
        {
            test3: '3',
            test4: true,
            abc: 'ignore me'
        },
        {
            test1: '12-12-2023',
            test3: '42',
            dummy1: 'ignore me'
        }
    ]
};

//output

let ouput = {
    rows: [{
            Test1: '10/12/2021',
            Test2: '4',
            Test3: '',
            Test4: ''
        },
        {
            Test1: '',
            Test2: '',
            Test3: '3',
            Test4: 'Y'
        },
        {
            Test1: '12/12/2023',
            Test2: '',
            Test3: '42',
            Test4: ''
        }
    ]
};

//function

function mapper(data1, data2) {
    let formattedValue = [];
    data2.value.forEach(val => {
        let data = {};
        for (let prop in val) {
            let name;
            const filter = data1.attributes.filter(el => el.Id === prop)[0];
            if (filter) {
                name = filter.Name;
                switch (filter.Type) {
                    case 'boolean':
                        data[name] =
                            val[prop] === true ? 'Y' : val[prop] === false ? 'N' : '';
                        break;
                    case 'date':
                        data[name] = new Date(val[prop]).toLocaleDateString();
                        break;
                    default:
                        data[name] = val[prop];
                        break;
                }
            }
        }
        formattedValue.push(data);
    });

    return formattedValue;
}

console.log(mapper(data1, data2));

same if I pass data2 as empty value I am looking to get below output

let data1 = {
  attributes: [
    {
      Id: 'test1',
      Name: 'Test1',
      Type: 'string'
    },
    {
      Id: 'test2',
      Name: 'Test2',
      Type: 'string'
    },
    {
      Id: 'test3',
      Name: 'Test3',
      Type: 'string'
    },
    {
      Id: 'test4',
      Name: 'Test4',
      Type: 'boolean'
    }
  ]
};

let data2 = {
  value: [
  ]
};

//output

let ouput = {
  rows: [
    {
      Test1: '',
      Test2: '',
      Test3: '',
      Test4: ''
    },
  ]
};
like image 289
Bravo Avatar asked May 17 '21 20:05

Bravo


People also ask

Do JavaScript maps have order?

The keys in Map are ordered in a simple, straightforward way: A Map object iterates entries, keys, and values in the order of entry insertion. Although the keys of an ordinary Object are ordered now, this was not always the case, and the order is complex.

What will happen when two objects with map method?

With a map method, you can order any number of objects by calling each object's map method once to map that object to a position on the axis used for the comparison, such as a number or date.

How do I iterate a map in JavaScript?

Iterate through a Map using JavaScript # Use the forEach() method to iterate over a Map object. The forEach method takes a function that gets invoked for each key/value pair in the Map , in insertion order. The function gets passed the value, key and the Map object on each iteration.


2 Answers

const data1 = {attributes:[{Id:'test1',Name:'Test1',Type:'date'},{Id:'test2',Name:'Test2',Type:'string'},{Id:'test3',Name:'Test3',Type:'string'},{Id:'test4',Name:'Test4',Type:'boolean'}]}
      data2 = {value:[{test1:'10-12-2021',test2:'4'},{test3:'3',test4:true},{test1:'12-12-2023',test3:'42'}]};
      data3 = {value: []}

const mapper = (x, y) => {
  const row = x.attributes.map(e => [e.Id, e.Name])
        format = e => { switch (true) {
            case typeof e === 'boolean':
              return e ? 'Y' : 'N'
            case isNaN(e) && !isNaN(Date.parse(e)):
              return new Date(e).toLocaleDateString()
            default: return e
          }}
  const rows = (y.value.length ? y.value : [1]).map(e => 
     Object.fromEntries(row.map(([k, v]) => [v, format(e[k]) ?? '']))
  )
  return { rows }
} 

console.log(mapper(data1, data2))
console.log(mapper(data1, data3))
.as-console-wrapper { max-height: 100% !important; top: 0; }

Explanation:

y.value.length ? y.value : [1]

Checks if data.value is empty, if not returns data.value. If yes returns array with 1 element (can be any value, it is just needed to do 1 iteration to meet your requirement about empty data, so value doesn't really matter here.

Rest of code should be pretty clear, if not, let me know.

like image 70
ulou Avatar answered Oct 09 '22 11:10

ulou


UPDATE

because you want minimum one set of values even data2.values is empty. My already given solution will work if we add empty object when array is empty, so adding below will fix it.

// I had to add below lines to get your desired result
// if `data2.value` is empty array
const arrayToLoop = [...data2.value];  
if(arrayToLoop.length === 0) {
  arrayToLoop.push({});
}

and now we will loop variable arrayToLoop rather than data2.value

also wrote small function used to convert the value as per given type, you can extend it as per your own need

function parseValue(type, value){
    if(value.length==0){
      return '';
    }
    switch(type.toLowerCase()){
      case 'boolean':
        return value === true ? 'Y' : value === false ? 'N' : '';
      case 'date':
        return new Date(value).toLocaleDateString();        
      default:
        return value;
    }
}

first I will get all the key and label mapping, and will look all the values for each key. notice how I done below.

let me know if you face any prob.

function parseValue(type, value){
    if(value.length==0){
      return '';
    }
    switch(type.toLowerCase()){
      case 'boolean':
        return value === true ? 'Y' : value === false ? 'N' : '';
      case 'date':
        return new Date(value).toLocaleDateString();        
      default:
        return value;
    }
}

function BusinessObjectMapper(data1, data2){
  const arrayToLoop = [...data2.value];  
  if(arrayToLoop.length === 0) {
      arrayToLoop.push({});
  }

  const rows = arrayToLoop.map(v=>{
     let r = {};
     data1.attributes.forEach(o=>{
      let {Id, Name, Type} = o;
      r[Name]=parseValue(Type, v[Id]||'');
     })
     return r;
  })
  
  return {
    rows
  };
}

let data1 = {
  attributes: [
    {
      Id: 'test1',
      Name: 'Test1',
      Type:'string'
    },
    {
      Id: 'test2',
      Name: 'Test2',
      Type:'boolean',
    },
    {
      Id: 'test3',
      Name: 'Test3',
      Type:'date'
    },
    {
      Id: 'test4',
      Name: 'Test4',
      Type:'un-known',
    }
  ]
};

let data2 = {
  value: [
    {
      test1: '1',
      test2: true
    },
    {
      test3: '02/02/2020',
      test4: '42'
    },
    {
      test1: 'deepak',
      test3: '01/01/2021'
    }
  ]
};

let data2_empty = {
  value: []
}

console.log(BusinessObjectMapper(data1, data2));
console.log(BusinessObjectMapper(data1, data2_empty));
like image 2
Deepak Sharma Avatar answered Oct 09 '22 11:10

Deepak Sharma