Refactor array of objects - javascript

The below code will have input as array of objects and I would like to convert into a different format.
The below code works fine but I need a more refactored shorter format of what I am trying to achieve.
var res = {"matchObject":"{\"data\":[{\"id\":\"jack1\",\"firstname\":\"jack\",\"lastname\":\"hudson\",\"dob\":\"1990-01-01T00:00:00.000Z\",\"email\":\"jack1#yahoo.com\",\"phone\":null,\"orgid\":\"001\"},{\"id\":\"jack2\",\"firstname\":\"Jack\",\"lastname\":\"Clinton\",\"dob\":\"1991-01-01T00:00:00.000Z\",\"email\":\"jack.clinton#yahoo.com\",\"phone\":\"+16464922600\",\"orgid\":\"002\"}]}"};
var parsedObj = JSON.parse(res.matchObject);
var res = [];
for(var key in parsedObj.data){
var emailObj = {};
var phoneObj = {}
if(parsedObj.data[key].email !== null){
emailObj.matchedRes = parsedObj.data[key].email;
emailObj.id = parsedObj.data[key].id;
emailObj.type = "email";
res.push(emailObj);
}
if(parsedObj.data[key].phone !== null){
phoneObj.matchedRes = parsedObj.data[key].phone;
phoneObj.id = parsedObj.data[key].id;
phoneObj.type="phone";
res.push(phoneObj);
}
}
console.log(res);
Desired output:
[ { matchedRes: 'jack1#yahoo.com', id: 'jack1', type: 'email' },
{ matchedRes: 'jack.clinton#yahoo.com', id: 'jack2', type: 'email' },
{ matchedRes: '+16464922600', id: 'jack2', type: 'phone' } ]
In the above code separate objects are created with phone and email for same id.

Here is a solution!
I just did a generic reducer, and then I use it on phone and email.
Then, I just spread the result of both calls to the result array :)
var res = {"matchObject":"{\"data\":[{\"id\":\"jack1\",\"firstname\":\"jack\",\"lastname\":\"hudson\",\"dob\":\"1990-01-01T00:00:00.000Z\",\"email\":\"jack1#yahoo.com\",\"phone\":null,\"orgid\":\"001\"},{\"id\":\"jack2\",\"firstname\":\"Jack\",\"lastname\":\"Clinton\",\"dob\":\"1991-01-01T00:00:00.000Z\",\"email\":\"jack.clinton#yahoo.com\",\"phone\":\"+16464922600\",\"orgid\":\"002\"}]}"};
var parsedObj = JSON.parse(res.matchObject);
const extractData = (obj, type) => obj.reduce((acc, elt) => (
elt[type] && acc.push({matchedRes: elt[type], id: elt.id, type: type})
, acc),[]);
const result = [...extractData(parsedObj.data, 'email'), ...extractData(parsedObj.data, 'phone')];
console.log(result);
Hope this helps, please do not hesitate to comment if you have any question ;)

You can use reduce with destructuring assignment . and check if email or phone is there than add a object accordingly
var res = {"matchObject":"{\"data\":[{\"id\":\"jack1\",\"firstname\":\"jack\",\"lastname\":\"hudson\",\"dob\":\"1990-01-01T00:00:00.000Z\",\"email\":\"jack1#yahoo.com\",\"phone\":null,\"orgid\":\"001\"},{\"id\":\"jack2\",\"firstname\":\"Jack\",\"lastname\":\"Clinton\",\"dob\":\"1991-01-01T00:00:00.000Z\",\"email\":\"jack.clinton#yahoo.com\",\"phone\":\"+16464922600\",\"orgid\":\"002\"}]}"};
var parsedObj = JSON.parse(res.matchObject);
let op = parsedObj.data.reduce((out,{id,email,phone})=>{
if(email){
out.push({matchedRes:email,id,type:`email`})
}
if(phone){
out.push({matchesRes:phone,id,type:`phone`})
}
return out
},[])
console.log(op)
If you want to see more use cases of You can destructuring assignment and it's uses you can check this one out

This should be possible with reduce:
var res = {"matchObject":"{\"data\":[{\"id\":\"jack1\",\"firstname\":\"jack\",\"lastname\":\"hudson\",\"dob\":\"1990-01-01T00:00:00.000Z\",\"email\":\"jack1#yahoo.com\",\"phone\":null,\"orgid\":\"001\"},{\"id\":\"jack2\",\"firstname\":\"Jack\",\"lastname\":\"Clinton\",\"dob\":\"1991-01-01T00:00:00.000Z\",\"email\":\"jack.clinton#yahoo.com\",\"phone\":\"+16464922600\",\"orgid\":\"002\"}]}"};
var parsedObj = JSON.parse(res.matchObject);
const keyFields = ["email", "phone"];
let result = parsedObj.data.reduce((acc, val) => {
keyFields.forEach(k => {
if (val[k]) acc.push({ matchedRes: val.email, id: val.id, type: k});
});
return acc;
}, []);
console.log("Result: ", result);

If you are looking for a little shorter code but still easy to read for anybody:
var res = {"matchObject":"{\"data\":[{\"id\":\"jack1\",\"firstname\":\"jack\",\"lastname\":\"hudson\",\"dob\":\"1990-01-01T00:00:00.000Z\",\"email\":\"jack1#yahoo.com\",\"phone\":null,\"orgid\":\"001\"},{\"id\":\"jack2\",\"firstname\":\"Jack\",\"lastname\":\"Clinton\",\"dob\":\"1991-01-01T00:00:00.000Z\",\"email\":\"jack.clinton#yahoo.com\",\"phone\":\"+16464922600\",\"orgid\":\"002\"}]}"};
var parsedObj = JSON.parse(res.matchObject);
var res = [];
Object.entries(parsedObj.data).forEach(el => {
el = el[1]
if(el.email !== null)
res.push({
matchedRes: el.email,
id: el.id,
type: "email"
})
if(el.phone !== null)
res.push({
matchedRes: el.phone,
id: el.id,
type: "phone"
})
})
console.log(res);

Related

Extract data from object based on key in JavaScript

I am trying to find the property value of an object based on key. I have below function getData which returns the data based on key passed as input parameter.
const getData = (key) => {
let row = {isSelected: true, Data: {Id: '1A', Value: 'LD'}};
return row[key];
}
console.log(getData('Data'));
In normal scenario it is working fine but how can I get the property value from nested object Data.Value.
If I call getData function as getData('Data.Value'), It should return LD.
You can use lodash's _.get() function that returns the value at a path:
const getData = path => {
const row = {isSelected: true, Data: {Id: '1A', Value: 'LD', InnerData: {Id: 1, Value: "Something"}}};
return _.get(row, path);
}
console.log(getData('Data'));
console.log(getData('Data.Value'));
console.log(getData('Data.InnerData.Value'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
I would suggest accessing the nested value like this:
getData("Data").Value
This is what you want. It is not matter how deep is your row. Try this. It would be multilevel nested object too. For example
Data.InnerData.Value...
const getData = (key) =>{
let row = {isSelected: true, Data: {Id: '1A', Value: 'LD', InnerData: {Id: 1, Value: "Something"}}};
var keys = key.split('.');
var res = row;
for(var i=0; i < keys.length; i++){
res = res[keys[i]];
}
return res;
}
console.log(getData('Data.InnerData.Value'));
When you have dynamic object keys you can use javascript Object.keys method.
var data = getData("Data")
var dynamicKeys = Object.keys(data)
for(int i=0; i < dynamicKeys.length; i++){
console.log(data[dynamicKeys[i]])
}
If you are certain that your object goes two level at most, you can try this simple solution
const isObject = (value) => {
return typeof value === 'object' && !Array.isArray(value) && value !== null;
};
const testData = { isSelected: true, data: { id: '1A', value: 'LD' } };
const getData = (key) => {
const keys = key.split('.');
if (isObject(testData[keys[0]])) {
return testData[keys[0]][keys[1]];
}
return testData[keys[0]];
};
console.log(getData('data.id'));

How to dynamically add data from an array with objects to a nested array?

I have this set of data that I get dynamically -
This is the data I dynamically get
and my question is how can I get the values from the key, pattern and label and put them in a nested object like this - how should the nested object look like.
My current code is
let mergeTagsObj = {};
const merg = function(arr){
const propertyDataMap = arr.map(x => x.key);
propertyDataMap.forEach(x => {
mergeTagsObj[x] = {}
});
console.log(mergeTagsObj);
// console.log(object);
};
merg(displayArr)
displayArr has the data that I dynamically get, and I map each one to get the key so I can then give the object property a name. But after that I need to get the other 2 (pattern and label) and put it in the mergeTagsObj;
ex: mergeTagsObj = {
firstName:{
name:{label}
value:{pattern}
},
...
};
You can add the pattern and label in your forEach and any other logic that you might need to transform the data.
const data = [{key: 'firstName', pattern: "{{firstName}}", label: "First Name"},
{key: 'lastName', pattern: "{{lastName}}", label: "Last Name"},
{key: 'unsubscribeLink', pattern: "{{unsubscribeLink}}", label: "Unsubscribe Link"}
]
const transformDataToTagsObject = (dData) => {
const dynamicData = {};
dData.forEach((currentData, index) => {
const currentKey = currentData.key
const name = currentData.label
let value = currentData.pattern
if(currentData.key === 'unsubscribeLink'){
value = `<a href='${value}'>Unsubscribe</a>`
}
dynamicData[currentKey] = {
name,
value
}
})
const tagsObject = {
tags: dynamicData
}
return tagsObject;
}
const finalResults = transformDataToTagsObject(data)
console.log(finalResults)
Not most elegant solution, but I think this should work. Don't need to create the array of keys first you can just iterate over the arr of objects.
const merg = function(arr){
arr.forEach(x => {
mergeTagsObj[x.key] = {};
mergeTagsObj[x.key]['name'] = x.label;
mergeTagsObj[x.key]['value'] = x.pattern
});
console.log(mergeTagsObj);
// console.log(object);
};
// Given
const data = [
{key: "firstName", pattern: "{{firstName}}", label: "First Name"},
{key: "unsubscribeLink", pattern: "{{unsubscribeLink}}", label: "Unsubscribe Link"}
];
const tagsObject = data.reduce((obj, item) => {
const key = item.key;
const name = item.label;
let value = item.pattern;
if (key === 'unsubscribeLink') value = 'Unsubscribe';
return {...obj, [key]: {name, value}};
}, {});
console.log(tagsObject);

Unable to parse this text to a JSON object

I have the following structure of info, that I need to convert into a JSON with properties and data. Originally its plain text, but I have converted it into an array to make it easier
[ '# Server',
'redis_version:5.0.5',
'redis_git_sha1:00000000',
'redis_git_dirty:0',
'redis_build_id:7983a619928f1f2d',
'redis_mode:standalone',
'os:Linux 3.10.0-693.5.2.el7.x86_64 x86_64',
'arch_bits:64',
'multiplexing_api:epoll',
'atomicvar_api:atomic-builtin',
'gcc_version:6.3.0',
'process_id:1',
'run_id:1348856f2bcc8af5cfef205f1880fedb68602201',
'tcp_port:6379',
'uptime_in_seconds:10484766',
'uptime_in_days:121',
'hz:10',
'configured_hz:10',
'lru_clock:11364638',
'executable:/data/redis-server',
'config_file:/etc/redis.conf',
'',
'# Clients',
'connected_clients:34',
'client_recent_max_input_buffer:2',
'client_recent_max_output_buffer:0',
'blocked_clients:0',
'',
'# Memory',
'used_memory:1568376',
'used_memory_human:1.50M',
'used_memory_rss:2768896',
'used_memory_rss_human:2.64M',
'used_memory_peak:5866848',
'used_memory_peak_human:5.60M',
'used_memory_peak_perc:26.73%',
'used_memory_overhead:1406080',
'used_memory_startup:791240',
'used_memory_dataset:162296',
'used_memory_dataset_perc:20.88%',
'allocator_allocated:1571256',
'allocator_active:2084864',
'allocator_resident:5722112',
'total_system_memory:33730531328',
'total_system_memory_human:31.41G',
'used_memory_lua:37888',
'used_memory_lua_human:37.00K' ]
And im trying to parse it into something that looks like the below structure
{
Server : {
redis_version : "5.0.5",
redis_git_sha1: "00000000"
...
},
Clients: {
connected_clientes: 54,
client_recent_max_input_buffer: 2,
...
}
Memory: {
used_memory: 1568376,
used_memory_human: "1.50M"
...
}
}
So far I have been able to create the subobjects
{ Server: {},
Clients: {},
Memory: {},
Persistence: {},
Stats: {},
Replication: {},
CPU: {},
Cluster: {},
Keyspace: {} }
Using this code where i managed to create the objects:
var obj = {};
console.log(lines)
for (let i in lines) {
if (lines[i].includes("#")) {
let prop = lines[i].toString()
let propFormat = prop.substring(2)
obj[propFormat] = {}
} else if (!lines[i].includes("#") && lines[i] != "") {
// console.log(lines[i])
}
}
But im stuck after that, can someone bring some light on how to continue?
I would use a forEach to loop through the array.
Then using .substring to check if it's a new 'key'; remember that key so you can add all the values, until the next key is found;
const data = [ '# Server', 'redis_version:5.0.5', 'redis_git_sha1:00000000', 'redis_git_dirty:0', 'redis_build_id:7983a619928f1f2d', 'redis_mode:standalone', 'os:Linux 3.10.0-693.5.2.el7.x86_64 x86_64', 'arch_bits:64', 'multiplexing_api:epoll', 'atomicvar_api:atomic-builtin', 'gcc_version:6.3.0', 'process_id:1', 'run_id:1348856f2bcc8af5cfef205f1880fedb68602201', 'tcp_port:6379', 'uptime_in_seconds:10484766', 'uptime_in_days:121', 'hz:10', 'configured_hz:10', 'lru_clock:11364638', 'executable:/data/redis-server', 'config_file:/etc/redis.conf', '', '# Clients', 'connected_clients:34', 'client_recent_max_input_buffer:2', 'client_recent_max_output_buffer:0', 'blocked_clients:0', '', '# Memory', 'used_memory:1568376', 'used_memory_human:1.50M', 'used_memory_rss:2768896', 'used_memory_rss_human:2.64M', 'used_memory_peak:5866848', 'used_memory_peak_human:5.60M', 'used_memory_peak_perc:26.73%', 'used_memory_overhead:1406080', 'used_memory_startup:791240', 'used_memory_dataset:162296', 'used_memory_dataset_perc:20.88%', 'allocator_allocated:1571256', 'allocator_active:2084864', 'allocator_resident:5722112', 'total_system_memory:33730531328', 'total_system_memory_human:31.41G', 'used_memory_lua:37888', 'used_memory_lua_human:37.00K' ];
// Result
let res = {};
// Remember latest prop
let latestProp = null;
// For each data entry
data.forEach((d) => {
// Starting with #: new key
const firstChar = d.substring(0, 1);
if (firstChar === '#') {
latestProp = d.substring(2);
res[latestProp] = {};
} else {
// Add key-value
let s = d.split(':');
if (s.length > 1) {
res[latestProp][s[0]] = s[1];
}
}
});
console.log(res);
My suggestion would be something like this:
//Declaring prop before the loop so that it isn't reset each iteration
let prop;
for(...) {
...
} else if (!lines[i].includes("#") && lines[i] != "") {
let split = lines[i].split(":");
let key = split[0];
let value = split[1];
obj[prop][key] = value
}
here is a working snippet using array.reduce , I also removed the "" values from the array
const tobeConverted= [ '# Server',
'redis_version:5.0.5',
'redis_git_sha1:00000000',
'redis_git_dirty:0',
'redis_build_id:7983a619928f1f2d',
'redis_mode:standalone',
'os:Linux 3.10.0-693.5.2.el7.x86_64 x86_64',
'arch_bits:64',
'multiplexing_api:epoll',
'atomicvar_api:atomic-builtin',
'gcc_version:6.3.0',
'process_id:1',
'run_id:1348856f2bcc8af5cfef205f1880fedb68602201',
'tcp_port:6379',
'uptime_in_seconds:10484766',
'uptime_in_days:121',
'hz:10',
'configured_hz:10',
'lru_clock:11364638',
'executable:/data/redis-server',
'config_file:/etc/redis.conf',
'# Clients',
'connected_clients:34',
'client_recent_max_input_buffer:2',
'client_recent_max_output_buffer:0',
'blocked_clients:0',
'# Memory',
'used_memory:1568376',
'used_memory_human:1.50M',
'used_memory_rss:2768896',
'used_memory_rss_human:2.64M',
'used_memory_peak:5866848',
'used_memory_peak_human:5.60M',
'used_memory_peak_perc:26.73%',
'used_memory_overhead:1406080',
'used_memory_startup:791240',
'used_memory_dataset:162296',
'used_memory_dataset_perc:20.88%',
'allocator_allocated:1571256',
'allocator_active:2084864',
'allocator_resident:5722112',
'total_system_memory:33730531328',
'total_system_memory_human:31.41G',
'used_memory_lua:37888',
'used_memory_lua_human:37.00K' ]
let index = 0;
let keys=[]
const reducedObj=tobeConverted.reduce((a,c)=>{
if(c.includes("#")){
const key= c.split("#")[1].trim()
keys.push(key)
index++;
return {...a,[key]:{}}
}else{
const split =c.split(":")
console.log(split)
const subkey =split[0].trim()
const subValue =split[1].trim()
a[keys[index-1]][subkey] = subValue;
}
return a
},{})
I think you can do something like this:
function parse (lines) {
const result = {};
let section;
lines.forEach((line) => {
if (line) {
if (line.startsWith('# ')) {
section = line.substring(2);
result[section] = {};
} else {
const [prop, value] = line.split(':');
result[section][prop] = value;
}
}
});
return result;
}
const textdata = [ '# Server', 'redis_version:5.0.5', 'redis_git_sha1:00000000', 'redis_git_dirty:0', 'redis_build_id:7983a619928f1f2d', 'redis_mode:standalone', 'os:Linux 3.10.0-693.5.2.el7.x86_64 x86_64', 'arch_bits:64', 'multiplexing_api:epoll', 'atomicvar_api:atomic-builtin', 'gcc_version:6.3.0', 'process_id:1', 'run_id:1348856f2bcc8af5cfef205f1880fedb68602201', 'tcp_port:6379', 'uptime_in_seconds:10484766', 'uptime_in_days:121', 'hz:10', 'configured_hz:10', 'lru_clock:11364638', 'executable:/data/redis-server', 'config_file:/etc/redis.conf', '', '# Clients', 'connected_clients:34', 'client_recent_max_input_buffer:2', 'client_recent_max_output_buffer:0', 'blocked_clients:0', '', '# Memory', 'used_memory:1568376', 'used_memory_human:1.50M', 'used_memory_rss:2768896', 'used_memory_rss_human:2.64M', 'used_memory_peak:5866848', 'used_memory_peak_human:5.60M', 'used_memory_peak_perc:26.73%', 'used_memory_overhead:1406080', 'used_memory_startup:791240', 'used_memory_dataset:162296', 'used_memory_dataset_perc:20.88%', 'allocator_allocated:1571256', 'allocator_active:2084864', 'allocator_resident:5722112', 'total_system_memory:33730531328', 'total_system_memory_human:31.41G', 'used_memory_lua:37888', 'used_memory_lua_human:37.00K' ];
const parsedObj = {};
for (data of textdata) {
// checking for keys
if (data.startsWith("#")) {
parsedObj[data.split(" ")[1]] = {};
continue;
}
if (Object.keys(parsedObj).length && data) {
let lastKeyFound = Object.keys(parsedObj).pop();
const [key, value] = data.split(':');
parsedObj[lastKeyFound][key] = value
}
}
// console.log(parsedObj)
// converting parsedObj to json
const textdataJson = JSON.stringify(parsedObj, null, 2)
console.log(textdataJson)

Modify object in Javascript

I'm trying to convert object
var data = {"USD": 12323,"CAD":32123}
to become
[{"id":"USD","value":12323},{"id":"CAD","value":32123}]
This is what i tried so far
var res = Object.keys(data).map(function(k) {
return [k, result[k]];
});
and get the result
[["USD", 12323],["CAD", 32123]]
Any help is very appreciated.
Thanks,
Just change your return statement to
return {id: k, value:result[k]}; //observe that an object is returned instead of an array
Demo
var data = {"USD": 12323,"CAD":32123};
var res = Object.keys(data).map(function(k) {
return {id: k, value:data[k]};
});
console.log( res );
You're creating one array, not an object. Change [] to {}:
var res = {"USD": 12323,"CAD":32123};
res = Object.keys(res).map(function(k) {
return {id: k, value:res[k]};
});
console.log(res);
as an alternative, you can use arrow function:
var res = {"USD": 12323,"CAD":32123};
res = Object.keys(res).map(x => x = { id: x, value: res[x]});
console.log(res);
or .every():
var res = {"USD": 12323,"CAD":32123};
var resWArrow = Object.entries(res).map(function(k) {
return {id: k[0], value: k[1]};
});
console.log('Without arrow: ' + JSON.stringify(resWArrow));
var resArrow = Object.entries(res).map(x => x = { id: x[0], value: x[1] });
console.log('With arrow: ' + JSON.stringify(resArrow));
With ES6, you could take Object.entries with Array#map and a destructuring assignment for the elements and short hand properties for the result.
var data = { "USD": 12323, "CAD": 32123 },
result = Object.entries(data).map(([id, value]) => ({ id, value }));
console.log(result);
You can iterate over the keys of the object and map them like follows:
Object.keys(res).map(function(key) {
return {id: key, value: data[key]};
}
Change the return statement and return an object
var res = {
"USD": 12323,
"CAD": 32123
}
var m = Object.keys(res).map(function(item) {
return {
id: item,
value: res[item]
}
})
console.log(m)

Removing object properties with Lodash

I have to remove unwanted object properties that do not match my model. How can I achieve it with Lodash?
My model is:
var model = {
fname: null,
lname: null
}
My controller output before sending to the server will be:
var credentials = {
fname: "xyz",
lname: "abc",
age: 23
}
I am aware I can use
delete credentials.age
but what if I have lots of unwanted properties? Can I achieve it with Lodash?
You can approach it from either an "allow list" or a "block list" way:
// Block list
// Remove the values you don't want
var result = _.omit(credentials, ['age']);
// Allow list
// Only allow certain values
var result = _.pick(credentials, ['fname', 'lname']);
If it's reusable business logic, you can partial it out as well:
// Partial out a "block list" version
var clean = _.partial(_.omit, _, ['age']);
// and later
var result = clean(credentials);
Note that Lodash 5 will drop support for omit
A similar approach can be achieved without Lodash:
const transform = (obj, predicate) => {
return Object.keys(obj).reduce((memo, key) => {
if(predicate(obj[key], key)) {
memo[key] = obj[key]
}
return memo
}, {})
}
const omit = (obj, items) => transform(obj, (value, key) => !items.includes(key))
const pick = (obj, items) => transform(obj, (value, key) => items.includes(key))
// Partials
// Lazy clean
const cleanL = (obj) => omit(obj, ['age'])
// Guarded clean
const cleanG = (obj) => pick(obj, ['fname', 'lname'])
// "App"
const credentials = {
fname:"xyz",
lname:"abc",
age:23
}
const omitted = omit(credentials, ['age'])
const picked = pick(credentials, ['age'])
const cleanedL = cleanL(credentials)
const cleanedG = cleanG(credentials)
Get a list of properties from model using _.keys(), and use _.pick() to extract the properties from credentials to a new object:
var model = {
fname:null,
lname:null
};
var credentials = {
fname:"xyz",
lname:"abc",
age:23
};
var result = _.pick(credentials, _.keys(model));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>
If you don't want to use Lodash, you can use Object.keys(), and Array.prototype.reduce():
var model = {
fname:null,
lname:null
};
var credentials = {
fname:"xyz",
lname:"abc",
age:23
};
var result = Object.keys(model).reduce(function(obj, key) {
obj[key] = credentials[key];
return obj;
}, {});
console.log(result);
You can easily do this using _.pick:
var model = {
fname: null,
lname: null
};
var credentials = {
fname: 'abc',
lname: 'xyz',
age: 2
};
var result = _.pick(credentials, _.keys(model));
console.log('result =', result);
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>
But you can simply use pure JavaScript (specially if you use ECMAScript 6), like this:
const model = {
fname: null,
lname: null
};
const credentials = {
fname: 'abc',
lname: 'xyz',
age: 2
};
const newModel = {};
Object.keys(model).forEach(key => newModel[key] = credentials[key]);
console.log('newModel =', newModel);
Lodash unset is suitable for removing a few unwanted keys.
const myObj = {
keyOne: "hello",
keyTwo: "world"
}
unset(myObj, "keyTwo");
console.log(myObj); /// myObj = { keyOne: "hello" }
Here I have used omit() for the respective 'key' which you want to remove... by using the Lodash library:
var credentials = [{
fname: "xyz",
lname: "abc",
age: 23
}]
let result = _.map(credentials, object => {
return _.omit(object, ['fname', 'lname'])
})
console.log('result', result)
You can use _.omit() for emitting the key from a JSON array if you have fewer objects:
_.forEach(data, (d) => {
_.omit(d, ['keyToEmit1', 'keyToEmit2'])
});
If you have more objects, you can use the reverse of it which is _.pick():
_.forEach(data, (d) => {
_.pick(d, ['keyToPick1', 'keyToPick2'])
});
To select (or remove) object properties that satisfy a given condition deeply, you can use something like this:
function pickByDeep(object, condition, arraysToo=false) {
return _.transform(object, (acc, val, key) => {
if (_.isPlainObject(val) || arraysToo && _.isArray(val)) {
acc[key] = pickByDeep(val, condition, arraysToo);
} else if (condition(val, key, object)) {
acc[key] = val;
}
});
}
https://codepen.io/aercolino/pen/MWgjyjm
This is my solution to deep remove empty properties with Lodash:
const compactDeep = obj => {
const emptyFields = [];
function calculateEmpty(prefix, source) {
_.each(source, (val, key) => {
if (_.isObject(val) && !_.isEmpty(val)) {
calculateEmpty(`${prefix}${key}.`, val);
} else if ((!_.isBoolean(val) && !_.isNumber(val) && !val) || (_.isObject(val) && _.isEmpty(val))) {
emptyFields.push(`${prefix}${key}`);
}
});
}
calculateEmpty('', obj);
return _.omit(obj, emptyFields);
};
For array of objects
model = _.filter(model, a => {
if (!a.age) { return a }
})
Recursively removing paths.
I just needed something similar, not removing just keys, but keys by with paths recursively.
Thought I'd share.
Simple readable example, no dependencies
/**
* Removes path from an object recursively.
* A full path to the key is not required.
* The original object is not modified.
*
* Example:
* const original = { a: { b: { c: 'value' } }, c: 'value' }
*
* omitPathRecursively(original, 'a') // outputs: { c: 'value' }
* omitPathRecursively(original, 'c') // outputs: { a: { b: {} } }
* omitPathRecursively(original, 'b.c') // { a: { b: {} }, c: 'value' }
*/
export const omitPathRecursively = (original, path, depth = 1) => {
const segments = path.split('.')
const final = depth === segments.length
return JSON.parse(
JSON.stringify(original, (key, value) => {
const match = key === segments[depth - 1]
if (!match) return value
if (!final) return omitPathRecursively(value, path, depth + 1)
return undefined
})
)
}
Working example: https://jsfiddle.net/webbertakken/60thvguc/1/
While looking for a solution that would work for both arrays and objects, I didn't find one and so I created it.
/**
* Recursively ignore keys from array or object
*/
const ignoreKeysRecursively = (obj, keys = []) => {
const keyIsToIgnore = (key) => {
return keys.map((a) => a.toLowerCase()).includes(key)
}
const serializeObject = (item) => {
return Object.fromEntries(
Object.entries(item)
.filter(([key, value]) => key && value)
.reduce((prev, curr, currIndex) => {
if (!keyIsToIgnore(curr[0]))
prev[currIndex] =
[
curr[0],
// serialize array
Array.isArray(curr[1])
? // eslint-disable-next-line
serializeArray(curr[1])
: // serialize object
!Array.isArray(curr[1]) && typeof curr[1] === 'object'
? serializeObject(curr[1])
: curr[1],
] || []
return prev
}, []),
)
}
const serializeArray = (item) => {
const serialized = []
for (const entry of item) {
if (typeof entry === 'string') serialized.push(entry)
if (typeof entry === 'object' && !Array.isArray(entry)) serialized.push(serializeObject(entry))
if (Array.isArray(entry)) serialized.push(serializeArray(entry))
}
return serialized
}
if (Array.isArray(obj)) return serializeArray(obj)
return serializeObject(obj)
}
// usage
const refObject = [{name: "Jessica", password: "ygd6g46"}]
// ignore password
const obj = ignoreKeysRecursively(refObject, ["password"])
// expects returned array to only have name attribute
console.log(obj)
let asdf = [{"asd": 12, "asdf": 123}, {"asd": 121, "asdf": 1231}, {"asd": 142, "asdf": 1243}]
asdf = _.map(asdf, function (row) {
return _.omit(row, ['asd'])
})

Categories

Resources