Create New Object key value pair base on array value - javascript

I need to generate csv for my client data but I need to include all headers came from my models.
The problem is some of my old client data has no existing fields. I want to create a new object with all the headers as a key and leave some empty string if a client has no data or no existing fields. Thanks for helping!
Here example of headers as key
let header = ["firstname", "lastname", "age", "gender", "address"];
Example for client info
let userInfo = [
{
firstname: "John",
lastname: "Doe",
age: "20",
gender: "male",
},
{
firstname: "Jane",
lastname: "Doe",
},
];
Expected Output
let userInfo = [
{
firstname: "John",
lastname: "Doe",
age: "20",
gender: "male",
address: "",
},
{
firstname: "Jane",
lastname: "Doe",
age: "",
gender: "",
address: "",
},
];

you can create an empty object with array.reduce
const emptyObj = header.reduce((acc, key) => {
acc[key] = "";
return acc;
}, {});
and use array.map on userInfo to return an object that concat the empty object with the one with value
let header = ["firstname", "lastname", "age", "gender", "address"];
let userInfo = [{
firstname: "John",
lastname: "Doe",
age: "20",
gender: "male",
},
{
firstname: "Jane",
lastname: "Doe",
},
];
const emptyObj = header.reduce((acc, key) => {
acc[key] = "";
return acc;
}, {});
const result = userInfo.map(user => {
return {
...emptyObj,
...user
};
})
console.log(result);

Related

if object has key from different array object key value, return only that key

I have 2 arrays.
One array contains some people objects, the other array contains objects with name key that holds the value needed from the people objects.
My solution so far but not getting any luck....
When mapping over people array how do I return only certain properties from person? Not the entire person object
const customContactValues = people.map((person) => { return valuesNeeded.filter((el) => (el.name in person) ? person[el.name] : "" ) })
console.log(customContactValues)
Here is my people array
const people = [
{
"foods": {
"favoriteFood": "Ice cream"
},
"firstName": "John",
"lastName": "Doe",
"age": 30
},
{
"foods": {
"favoriteFood": "pizza"
},
"firstName": "Jane",
"lastName": "Doe",
"age": 39
},
{
"foods": {
"favoriteFood": "pbj"
},
"firstName": "Kevin",
"lastName": "Baker",
"age": 22
},
{
"foods": {
"favoriteFood": "pushpops"
},
"firstName": "ernie",
"lastName": "duncan",
"age": 29
},
]
Here is the values array which contains the keys I need from people array
const valuesNeeded = [
{ name: 'firstName' },
{ name: 'lastName' },
{ name: 'favoriteFood' }
]
I am trying to get and output like this below
const desiredResult = [
{firstName: "John", lastName: "Doe", favoriteFood: "Ice cream"},
{firstName: "Jane", lastName: "Doe", favoriteFood: "Pizza"},
{firstName: "Kevin", lastName: "Baker", favoriteFood: "pbj"},
{firstName: "ernie", lastName: "duncan", favoriteFood: "pushpops"}
]
filter only filters elements from array based on some condition but in your case we don't want to filter elements we just want to create new array of objects from and existing array so map function is a good start.
Second problem is the object can contain nested object which may contain required key value pair so to retrieve them we can recursively look over the value which is object if we don't find the key value directly in the object.
And since we don't want all the key value for each object in array we can either create a new object or delete from existing object, keeping the original is good and safe option if required for further processing.
const people = [{
"foods": {
"favoriteFood": "Ice cream"
},
"firstName": "John",
"lastName": "Doe",
"age": 30
},
{
"foods": {
"favoriteFood": "pizza"
},
"firstName": "Jane",
"lastName": "Doe",
"age": 39
},
{
"foods": {
"favoriteFood": "pbj"
},
"firstName": "Kevin",
"lastName": "Baker",
"age": 22
},
{
"foods": {
"favoriteFood": "pushpops"
},
"firstName": "ernie",
"lastName": "duncan",
"age": 29
},
];
// function to retrieve the key value recursively
function valueByKey(obj, key) {
let value = obj[key];
if (value) {
return value;
}
Object.keys(obj).forEach(function(k) {
if (typeof obj[k] == 'object') {
value = valueByKey(obj[k], key);
}
});
return value;
}
const valuesNeeded = [{
name: 'firstName'
},
{
name: 'lastName'
},
{
name: 'favoriteFood'
}
];
// creating new object by passing the current object and key
let output = people.map(function(item) {
let result = {};
valuesNeeded.forEach(function(obj) {
result[obj.name] = valueByKey(item, obj.name);
});
return result;
});
console.log(output);
You can search for the desired key on the top level, and go to child objects if not found. Here is my approach :
function getValue(obj, key) {
const keys = Object.keys(obj);
// Check if key exist on this level
if (keys.includes(key)) {
return obj[key];
} else {
// else we try to find in child objects
for (k of keys) {
if (typeof obj[k] == 'object') {
return getValue(obj[k], key);
}
}
}
//Return this if not found
return '';
}
const people = [
{
foods: {
favoriteFood: 'Ice cream',
},
firstName: 'John',
lastName: 'Doe',
age: 30,
},
{
foods: {
favoriteFood: 'pizza',
},
firstName: 'Jane',
lastName: 'Doe',
age: 39,
},
{
foods: {
favoriteFood: 'pbj',
},
firstName: 'Kevin',
lastName: 'Baker',
age: 22,
},
{
foods: {
favoriteFood: 'pushpops',
},
firstName: 'ernie',
lastName: 'duncan',
age: 29,
},
];
const valuesNeeded = [
{ name: 'firstName' },
{ name: 'lastName' },
{ name: 'favoriteFood' },
];
let output = people.map((item) => {
let result = {};
valuesNeeded.forEach(function (obj) {
result[obj.name] = getValue(item, obj.name);
});
return result;
});
console.log(output);
Edit 1 : You can further simplify valuesNeeded to keysNeeded and store only the keys in an array like this keysNeeded = ['firatName', 'lastName', 'favoriteFood']. Please change invocation accordingly.

Best way to replace item in object?

I will fetch this data, the data is always diffrent. Sometimes admin exist sometimes not.
What is the best way to remove all the values in admin and add new value, if admin key exist?
const apiFetched = [{
persons: {
firstName: "John",
lastName: "Doe",
},
admin: {
firstName: "Jeff",
lastName: "Pan",
}
}]
If admin key exist I would like to replace everything in admin and add these:
{ firstName: "Alan", lastName: "Jack" }
like this:
const apiFetched = [{
persons: {
firstName: "John",
lastName: "Doe",
},
admin: {
firstName: "Alan",
lastName: "Jack",
},
}];
iterate the array via forEach
for each item which features an own admin property ...
assign to this item's admin property/object another object like superUser which can feature equally named and/or additional properties ...
in the 1st case, key-value pairs will be replaced/overwritten,
in the 2nd case the admin object would aggregate/accumulate new entries.
const apiFetched = [{
persons: {
firstName: "John",
lastName: "Doe",
},
admin: {
firstName: "Jeff",
lastName: "Pan",
},
}];
const superUser = { firstName: "Alan", lastName: "Jack" };
apiFetched
.forEach(item => {
if (item.hasOwnProperty('admin')) {
Object.assign(item.admin, superUser);
}
});
console.log({ apiFetched });
.as-console-wrapper { min-height: 100%!important; top: 0; }
Here you go:
const apiFetched = [{
persons: {
firstName: "John",
lastName: "Doe",
},
admin: {
firstName: "Jeff",
lastName: "Pan",
}
}]
apiFetched.forEach(i => {
if (i.admin) {
i.admin = {
firstname: "Alan",
lastname: "Jack"
}
}
})
console.log(apiFetched)

Compare typescript objects and add diff to new object

Within my Angular application, I need to compare two typescript objects and create a new object that consists of key/value pairs where the value of the key is different in the second object.
Here is my code:
const objBefore = {id: 100088, firstName: "Joe", lastName: "Smith", notes: null};
const objAfter = {id: 100088, firstName: "John", lastName: "Johnson", notes: null};
let newObj = {};
for(let key in objBefore) {
if (objBefore[key] !== objAfter[key]) {
let newEntry = { key: objAfter[key]}
Object.assign(newObj, newEntry)
}
}
console.log(newObj)
The output is:
{ key: 'Johnson' }
I need the output to be:
{ firstName: "John", lastName: "Johnson" }
How do I assign the value of the key (e.g., firstName) instead of the variable (key)?
Just use square brackets on [key]
const objBefore = {id: 100088, firstName: "Joe", lastName: "Smith", notes: null};
const objAfter = {id: 100088, firstName: "John", lastName: "Johnson", notes: null};
let newObj = {};
for(let key in objBefore) {
if (objBefore[key] !== objAfter[key]) {
let newEntry = { [key]: objAfter[key]}
Object.assign(newObj, newEntry)
}
}

How to merge an array of objects keep only properties in the first array

I have a working function that merges two arrays of objects by property a1 and a1. The solution was based on answers to some similar questions, however my requirement is to keep only the properties in the original array a1.
How can I adjust this function to return an array of objects containing only the properties in the first array?
Here is a JS fiddle with example data. Note that the output is logged to the console. Also note that the solution must be in vanilla Javascript ES6.
https://jsfiddle.net/dba9r3sf/
const a1 = [
{
FirstName: "John",
LastName: "Doe",
Age: 33,
Username: "jdoe"
},
{
FirstName: "Mary",
LastName: "Bloom",
Age: 63,
Username: "mbloom"
},
{
FirstName: "Alex",
LastName: "Arias",
Age: 21,
Username: "aarias"
}
];
const a2 = [
{
FirstName: "Johnathan",
LastName: "Doe",
Age: 34,
Username: "jdoe",
Job: "Graphic Designer"
},
{
FirstName: "Mary-Anne",
LastName: "Bloom",
Age: 64,
Username: "mbloom",
Job: "Investor"
},
{
FirstName: "Alex",
LastName: "Arias",
Age: 22,
Username: "aarias",
Job: "Student"
}
];
/**
* Merge an array of objects by property
* #param {array} a1 array 1 destination to be merged into
* #param {array} a2 array 2 source to be merged, overwrites existing values in a1
* #param {string} prop name of property to match for merge
* TODO: Set properties that exist on a1 only otherwise ignore
*/
function mergeByProperty(a1, a2, prop) {
let merged = [];
for (let i = 0; i < a1.length; i++) {
merged.push({
...a1[i],
...(a2.find((itmInner) => itmInner[prop] === a1[i][prop]))
});
}
return merged;
}
let result = mergeByProperty(a1, a2, 'Username');
console.log(JSON.stringify(result));
// Output:
[{"FirstName":"Johnathan","LastName":"Doe","Age":34,"Username":"jdoe","Job":"Graphic Designer"},{"FirstName":"Mary-Anne","LastName":"Bloom","Age":64,"Username":"mbloom","Job":"Investor"},{"FirstName":"Alex","LastName":"Arias","Age":22,"Username":"aarias","Job":"Student"}]
// Desired output (no "Job" property because that does not exist in the first array of objects):
[{"FirstName":"Johnathan","LastName":"Doe","Age":34,"Username":"jdoe"},{"FirstName":"Mary-Anne","LastName":"Bloom","Age":64,"Username":"mbloom},{"FirstName":"Alex","LastName":"Arias","Age":22,"Username":"aarias"}]
You can take keys form first array and then select corresponding key/value pair form second array
const a1 = [{FirstName: "John",LastName: "Doe",Age: 33,Username: "jdoe"},{FirstName: "Mary",LastName: "Bloom",Age: 63,Username: "mbloom"},{FirstName: "Alex",LastName: "Arias",Age: 21,Username: "aarias"}];
const a2 = [{FirstName: "Johnathan",LastName: "Doe",Age: 34,Username: "jdoe",Job: "Graphic Designer"},{FirstName: "Mary-Anne",LastName: "Bloom",Age: 64,Username: "mbloom",Job: "Investor"},{FirstName: "Alex",LastName: "Arias",Age: 22,Username: "aarias",Job: "Student"}];
function mergeByProperty(a1, a2, prop) {
let merged = [];
for (let i = 0; i < a1.length; i++) {
let found = a2.find((itmInner) => itmInner[prop] === a1[i][prop])
if(found){
found = Object.keys(a1[0]).reduce((op,inp)=>{
op[inp] = found[inp]
return op
},{})
}
merged.push({
...a1[i],
...found
});
}
return merged;
}
let result = mergeByProperty(a1, a2, 'Username');
console.log((result));
You can create a username map from a2 then simply Array.map over the a1 array and merge with a custom merge function which does nothing more than Array.reduce over the keys of a1 and assigns the values from a2:
const a1 = [ { FirstName: "John", LastName: "Doe", Age: 33, Username: "jdoe" }, { FirstName: "Mary", LastName: "Bloom", Age: 63, Username: "mbloom" }, { FirstName: "Alex", LastName: "Arias", Age: 21, Username: "aarias" } ];
const a2 = [ { FirstName: "Johnathan", LastName: "Doe", Age: 34, Username: "jdoe", Job: "Graphic Designer" }, { FirstName: "Mary-Anne", LastName: "Bloom", Age: 64, Username: "mbloom", Job: "Investor" }, { FirstName: "Alex", LastName: "Arias", Age: 22, Username: "aarias", Job: "Student" } ];
let obj = a2.reduce((r,c) => (r[c.Username] = c, r), {}) // username map
let merge = (a, b, props) => props.reduce((r,c) => (r[c] = b[c], r), a)
let result = a1.map(x => merge(x, obj[x.Username], Object.keys(x)))
console.log(result)
You can do something like this:
const a1 = [
{
FirstName: "John",
LastName: "Doe",
Age: 33,
Username: "jdoe"
},
{
FirstName: "Mary",
LastName: "Bloom",
Age: 63,
Username: "mbloom"
},
{
FirstName: "Alex",
LastName: "Arias",
Age: 21,
Username: "aarias"
}
];
const a2 = [
{
FirstName: "Johnathan",
LastName: "Doe",
Age: 34,
Username: "jdoe",
Job: "Graphic Designer"
},
{
FirstName: "Mary-Anne",
LastName: "Bloom",
Age: 64,
Username: "mbloom",
Job: "Investor"
},
{
FirstName: "Alex",
LastName: "Arias",
Age: 22,
Username: "aarias",
Job: "Student"
}
];
const result = a1.map((obj1, index) => {
const obj2 = a2[index];
if (obj2) {
return Object.keys(obj1).reduce((acc, key) => {
acc[key] = obj2[key];
return acc;
}, {});
}
return obj1;
}, []);
console.log(result);

javascript count objects in array of objects without null values

Let's say we have array of objects:
const data = [
{
firstName: "Bruce",
lastName: "Wayne",
address: "Arkham 6",
id: "1",
},
{
firstName: "Peter",
lastName: "Parker",
address: "LA 54",
id: "2"
},
{
firstName: "Tony",
lastName: "Stark",
address: null,
id: "3"
}
];
and want to get length of the array but exclude counting of the objects which has null values (in example above, this is the last object with address property null) so that result of the counting of the example above would be 2.
objectsWithoutNull = data.reduce(function (r, a) {
return r + +( a!== null);
}, 0);
I'm trying with reduce method, but got 0.
Where is the problem in iteration?
You can filter() the array and than get object values and check where not includes null.
const data = [
{
firstName: "Bruce",
lastName: "Wayne",
address: "Arkham 6",
id: "1",
},
{
firstName: "Peter",
lastName: "Parker",
address: "LA 54",
id: "2"
},
{
firstName: "Tony",
lastName: "Stark",
address: null,
id: "3"
}
];
const notNullable = data.filter(obj=>!Object.values(obj).includes(null));
console.log(notNullable)
console.log(notNullable.length)
More about Object Values Filter Includes
Reduce the array, for each object get the values with Object.values(), and check with Array.includes() if it contains a null value. Negate with ! the boolean result of inclues, and use the + operator to convert to number. Add the number to the accumulator.
const data = [{"firstName":"Bruce","lastName":"Wayne","address":"Arkham 6","id":"1"},{"firstName":"Peter","lastName":"Parker","address":"LA 54","id":"2"},{"firstName":"Tony","lastName":"Stark","address":null,"id":"3"}];
const result = data.reduce((r, o) =>
r + +!Object.values(o).includes(null)
, 0);
console.log(result);
An option is to iterate over the object-values of a and test if the value is equal to null. If we found a null don't increase our counter.
const data = [
{
firstName: "Bruce",
lastName: "Wayne",
address: "Arkham 6",
id: "1",
},
{
firstName: "Peter",
lastName: "Parker",
address: "LA 54",
id: "2"
},
{
firstName: "Tony",
lastName: "Stark",
address: null,
id: "3"
}
];
let objectsWithoutNull = data.reduce(function (r, a) {
let hasNull = false;
const values = Object.values(a);
values.map(v => {
if (v === null) {
hasNull = true;
}
});
return r + !hasNull;
}, 0);
console.log(objectsWithoutNull);
objectsWithoutNull = data.reduce(function (r, a) {
return r + +( Object.values(a).indexOf(null) == -1);
}, 0);
This will work if you want to check for all the properties!
You can use Array.prototype.every to check that all the values are not null
var length = data.filter(i => Object.values(i).every(i => i !== null)).length
If you are using lodash.
const data = [
{
firstName: "Bruce",
lastName: "Wayne",
address: "Arkham 6",
id: "1",
},
{
firstName: "Peter",
lastName: "Parker",
address: "LA 54",
id: "2"
},
{
firstName: "Tony",
lastName: "Stark",
address: null,
id: "3"
}
];
const counter = _.filter(data, ({address}) => {return address != null}).length;
console.log(counter);

Categories

Resources