delete an object in a nested array which has key value - javascript

i want to delete the only low-level object(for example in below code, under personal data there are two objects... i want to delete one object where action: old) under each section, where "action": "OLD"
I'm using lodash in my project
[
{
"clientDetails": {
"personalData": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
},
"clientAddress": {
"primaryAddress": [
{
"action": "OLD",
"id": "12345"
},
{
"action": "NEW",
"id": "12445"
}
],
"secondaryAddress": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
}
},
{
"clientDemise": {
"deathDetails": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
},
"clientMarital": {
"divorceInformation": [
{
"action": "OLD",
"id": "12345"
},
{
"action": "NEW",
"id": "12445"
}
],
"marraigeInformation": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
}
}
]
sorry for the wrong presentation, this is the first time I'm posting a question

Just few lines can achieve this considering
input = your input
This peace of code will do the work
for (var i of input) {
for (var j in i) {
var ob = i[j];
for (var k in ob) {
var index = _.findIndex(ob[k], {'action': 'OLD'});
if (index > -1) {
ob[k].splice(index, 1);
}
}
}
}

You can achieve this via something like this without lodash:
var data = [{ "clientDetails": { "personalData": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] }, "clientAddress": { "primaryAddress": [{ "action": "OLD", "id": "12345" }, { "action": "NEW", "id": "12445" } ], "secondaryAddress": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] } }, { "clientDemise": { "deathDetails": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] }, "clientMarital": { "divorceInformation": [{ "action": "OLD", "id": "12345" }, { "action": "NEW", "id": "12445" } ], "marraigeInformation": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] } } ]
const removeOld = (data) => data.map(x =>
Object.entries(x).reduce((r, [k,v]) => {
r[k] = Object.entries(v).map(([o,p]) =>
({[o]: p.filter(n => n.action != 'OLD')}))
return r
},{}))
console.log(removeOld(data))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Using map, Object.entries, reduce and filter.
Another way would be to utilize recursion similar to #Vanojx1 approach but in ES6:
var data = [{ "clientDetails": { "personalData": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] }, "clientAddress": { "primaryAddress": [{ "action": "OLD", "id": "12345" }, { "action": "NEW", "id": "12445" } ], "secondaryAddress": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] } }, { "clientDemise": { "deathDetails": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] }, "clientMarital": { "divorceInformation": [{ "action": "OLD", "id": "12345" }, { "action": "NEW", "id": "12445" } ], "marraigeInformation": [{ "action": "NEW", "id": "12345" }, { "action": "OLD", "id": "12445" } ] } } ]
const removeOld = (data) =>
Array.isArray(data) ? data.filter(x => x.action != 'OLD').map(x => removeOld(x)) :
typeof(data) == 'object' ? Object.entries(data).reduce((r, [k,v]) => (r[k] = removeOld(v), r), {}) :
data
console.log(removeOld(data))

You can use JavaScript filters. Reduce your bundle size by not using lodash.
// it's upto you, you can use new Array() as well and insert if(ktm.action==='NEW')
clients = clients.filter(function(itm) {
Object.keys(itm).forEach(function(Okey, Ovalue) {
Object.keys(itm[Okey]).forEach(function(inkey, invalue) {
itm[Okey][inkey].filter(function(ktm) {
if (ktm.action === 'OLD') {
// perform your logic, either you can insert into new Array() or
// delete that object and return clients
}
});
});
});
});

If the structure of your data is going to be fairly consistent (i.e. similar to what you've included in your question), you could do something like this:
const mapObj = (f, obj) => {
return Object.keys(obj).reduce((acc, key) => {
acc[key] = f(obj[key], key)
return acc
}, {})
}
const filterData = data => {
// the data itself is an array, so iterate over each item in the array
return data.map(x1 => {
// x1 is an object, so need to iterate over each item in the object
return mapObj(x2 => {
// x2 is an object, so need to iterate over each item in the object
return mapObj(x3 => {
// x3 is an array of objects. each item in the array has an action key which could equal "NEW" or "OLD". get rido of the items with action === "OLD"
return x3.filter(x4 => x4.action !== "OLD")
}, x2)
}, x1)
})
}
const data = [
{
"clientDetails": {
"personalData": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
},
"clientAddress": {
"primaryAddress": [
{
"action": "OLD",
"id": "12345"
},
{
"action": "NEW",
"id": "12445"
}
],
"secondaryAddress": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
}
},
{
"clientDemise": {
"deathDetails": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
},
"clientMarital": {
"divorceInformation": [
{
"action": "OLD",
"id": "12345"
},
{
"action": "NEW",
"id": "12445"
}
],
"marraigeInformation": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
}
}
]
const result = filterData(data)
console.log(result)
If you want a more generic solution that can take data of any structure and just removes all objects with an action equal to 'OLD':
const reduceObj = (f, initial, obj) => {
return Object.keys(obj).reduce((acc, key) => {
return f(acc, obj[key], key)
}, initial)
}
const isObject = x => x !== null && typeof x === 'object'
const removeAllOld = data => {
if(Array.isArray(data)) {
return data.reduce((acc, value) => {
// don't include the item if it has a key named 'action' that is equal to 'OLD'
if(value.action && value.action === 'OLD') return acc
acc.push(removeAllOld(value))
return acc
}, [])
}
else if(isObject(data)) {
return reduceObj((acc, value, key) => {
// don't include the item if it has a key named 'action' that is equal to 'OLD'
if(value.action && value.action === 'OLD') return acc
acc[key] = removeAllOld(value)
return acc
}, {}, data)
}
else {
return data
}
}
const data = [
{
"clientDetails": {
"personalData": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
},
"clientAddress": {
"primaryAddress": [
{
"action": "OLD",
"id": "12345"
},
{
"action": "NEW",
"id": "12445"
}
],
"secondaryAddress": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
}
},
{
"clientDemise": {
"deathDetails": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
},
"clientMarital": {
"divorceInformation": [
{
"action": "OLD",
"id": "12345"
},
{
"action": "NEW",
"id": "12445"
}
],
"marraigeInformation": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
}
}
]
console.log(removeAllOld(data))

Structure independent solution checking for action in each object node
var data=[{clientDetails:{personalData:[{action:"NEW",id:"12345"},{action:"OLD",id:"12445"}]},clientAddress:{primaryAddress:[{action:"OLD",id:"12345"},{action:"NEW",id:"12445"}],secondaryAddress:[{action:"NEW",id:"12345"},{action:"OLD",id:"12445"}]}},{clientDemise:{deathDetails:[{action:"NEW",id:"12345"},{action:"OLD",id:"12445"}]},clientMarital:{divorceInformation:[{action:"OLD",id:"12345"},{action:"NEW",id:"12445"}],marraigeInformation:[{action:"NEW",id:"12345"},{action:"OLD",id:"12445"}]}}];
const reducer = (curr) => {
if(_.isArray(curr))
return _(curr)
.filter(el => !('action' in el && el.action == 'OLD'))
.map(el => reducer(el))
.value()
else if(_.isObject(curr)) {
return _(curr)
.mapValues(el => reducer(el))
.value()
} else
return curr;
};
console.log(reducer(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

you can do a deep copy like this:
const array = [
{
"clientDetails": {
"personalData": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
},
"clientAddress": {
"primaryAddress": [
{
"action": "OLD",
"id": "12345"
},
{
"action": "NEW",
"id": "12445"
}
],
"secondaryAddress": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
}
},
{
"clientDemise": {
"deathDetails": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
},
"clientMarital": {
"divorceInformation": [
{
"action": "OLD",
"id": "12345"
},
{
"action": "NEW",
"id": "12445"
}
],
"marraigeInformation": [
{
"action": "NEW",
"id": "12345"
},
{
"action": "OLD",
"id": "12445"
}
]
}
}
]
function removeOldAction(a) {
if (a instanceof Array) {
let copiee = [];
for (let item in a) {
const propValue = removeOldAction(a[item]);
if(propValue) {
copiee.push(propValue);
}
}
return copiee;
}
if (a instanceof Object) {
if (a['action'] === 'OLD') {
return;
}
let copiee = {};
for (let key in a) {
copiee[key] = removeOldAction(a[key]);
}
return copiee;
}
return a;
}
console.log(removeOldAction(array));

Let's not mutate the original input data, clone it with a customizer, and reject the unwanted stuffs (if they exists) inside the customizer to have cleaner cloned output as expected. You can use lodash#cloneDeepWith
_.cloneDeepWith(input, v => _.find(v, {action: "OLD"}) ? _.reject(v, {action: "OLD"}) : undefined);
This is just an example of having (hard coded) of what you want to reject. but you can wrap this in a call back and take the reject criteria as an argument to make it dynamic.
So here we go:
let input = [{"clientDetails":{"personalData":[{"action":"NEW","id":"12345"},{"action":"OLD","id":"12445"}]},"clientAddress":{"primaryAddress":[{"action":"OLD","id":"12345"},{"action":"NEW","id":"12445"}],"secondaryAddress":[{"action":"NEW","id":"12345"},{"action":"OLD","id":"12445"}]}},{"clientDemise":{"deathDetails":[{"action":"NEW","id":"12345"},{"action":"OLD","id":"12445"}]},"clientMarital":{"divorceInformation":[{"action":"OLD","id":"12345"},{"action":"NEW","id":"12445"}],"marraigeInformation":[{"action":"NEW","id":"12345"},{"action":"OLD","id":"12445"}]}}],
clear = (input, rej) => (
_.cloneDeepWith(input, v => _.find(v, rej) ? _.reject(v, rej) : undefined)
),
res;
res = clear(input, {action: "OLD"}); //you can filter out action: OLD
console.log(res);
res = clear(input, {action: "NEW"}); //you can filter out action: NEW
console.log(res);
res = clear(input, d => d.action==="OLD"); //you can filter with custom callback with complex logic
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Related

How do I destructure this deep nested json objects and map it in JS

I have a nested array like below. There are about 100 de objects in the array. The de objects also have deg[0] array but most likely I will only have the first index. Now the trick is that the de are subset of deg. Which means each deg can have say 10 de. How can I retrieve the deg and there associated de and map it into a new array like:
newArray = [
deg1: [
{de1},
{de2}
],
deg2: [
{de1},
{de2}
]
]
Here is my nested array. I posted four but the list is over a 100.
{
"name": "Report",
"id": "2YYUEZ6I1r9",
"dse1": [
{
"de1": {
"name": "Number",
"id": "HjMOngg3kuy",
"de1-av": [
{
"value": "FHaQMPv9zc7",
"attribute": {
"id": "uwVkIP7PZDt"
}
},
{
"value": "something",
"attribute": {
"id": "FHaQMPv9zc7"
}
}
],
"deg1": [
{
"name": "TB",
"id": "2XJB1JO9qX8"
}
]
}
},
{
"de2": {
"name": "Number of",
"id": "a3dtGETTawy",
"de2-av": [
{
"value": "FHaQMPv9zc7",
"attribute": {
"id": "uwVkIP7PZDt"
}
},
{
"value": "something",
"attribute": {
"id": "FHaQMPv9zc7"
}
}
],
"deg1": [
{
"name": "Secondary",
"id": "w99RWzXHgtw"
}
]
}
},
{
"de1": {
"name": "Number of",
"id": "a3dtGETTawy",
"de1av": [
{
"value": "FHaQMPv9zc7",
"attribute": {
"id": "uwVkIP7PZDt"
}
},
{
"value": "something",
"attribute": {
"id": "FHaQMPv9zc7"
}
}
],
"deg2": [
{
"name": "Secondary",
"id": "w99RWzXHgtw"
}
]
}
},
{
"de2": {
"name": "Number of",
"id": "a3dtGETTawy",
"de2av": [
{
"value": "FHaQMPv9zc7",
"attribute": {
"id": "uwVkIP7PZDt"
}
},
{
"value": "something",
"attribute": {
"id": "FHaQMPv9zc7"
}
}
],
"deg2": [
{
"name": "Tertiary",
"id": "w99RWzXHgtw"
}
]
}
}
]
}
Group array of objects by property (this time a property to be matched by a reg exp) using Array.reduce.
Update: Ignoring missing keys.
var input={name:"Report",id:"2YYUEZ6I1r9",dse1:[{de1:{name:"Number",id:"HjMOngg3kuy","de1-av":[{value:"FHaQMPv9zc7",attribute:{id:"uwVkIP7PZDt"}},{value:"something",attribute:{id:"FHaQMPv9zc7"}}],deg1:[{name:"TB",id:"2XJB1JO9qX8"}]}},{de2:{name:"Number of",id:"a3dtGETTawy","de2-av":[{value:"FHaQMPv9zc7",attribute:{id:"uwVkIP7PZDt"}},{value:"something",attribute:{id:"FHaQMPv9zc7"}}],deg1:[{name:"Secondary",id:"w99RWzXHgtw"}]}},{de1:{name:"Number of",id:"a3dtGETTawy",de1av:[{value:"FHaQMPv9zc7",attribute:{id:"uwVkIP7PZDt"}},{value:"something",attribute:{id:"FHaQMPv9zc7"}}],deg2:[{name:"Secondary",id:"w99RWzXHgtw"}]}},{de2:{name:"Number of",id:"a3dtGETTawy",de2av:[{value:"FHaQMPv9zc7",attribute:{id:"uwVkIP7PZDt"}},{value:"something",attribute:{id:"FHaQMPv9zc7"}}],deg2:[{name:"Tertiary",id:"w99RWzXHgtw"}]}}]}
var reg = new RegExp("^de[0-9]+$");
var reg2 = new RegExp("^deg[0-9]+$");
let obj = input['dse1'].reduce(function(agg, item) {
// do your group by logic below this line
var key = Object.keys(item).find(function(key) {
return key.match(reg) ? key : null;
})
if (key) {
var key2 = Object.keys(item[key]).find(function(key) {
return key.match(reg2) ? key : null;
})
agg[key] = agg[key] || [];
if (key2) {
var to_push = {}
to_push[key2] = item[key][key2]
agg[key].push(to_push)
}
}
// do your group by logic above this line
return agg
}, {});
console.log(obj)
.as-console-wrapper {
max-height: 100% !important;
}

Generate dynamic payload as per nested array item click javascript

I have this JSON data:
{
"data": [
{
"category": {
"documentId": "c8kr0cv012vtr8vm3iug",
"title": "Art"
},
"subcategories": [
{
"documentId": "c8kr7nv012vtr8vm3l8g",
"title": "Architecture"
},
{
"documentId": "c8kr7nv012vtr8vm3lag",
"title": "Dance"
},
{
"documentId": "c8kr7nv012vtr8vm3lbg",
"title": "Fashion"
}
]
},
{
"category": {
"documentId": "c8kr0cv012vtr8vm3iqg",
"title": "Business"
},
"subcategories": [
{
"documentId": "c8kr3d7012vtr8vm3jjg",
"title": "Crypto"
},
{
"documentId": "c8kr3d7012vtr8vm3jj0",
"title": "Finance"
},
{
"documentId": "c8kr3d7012vtr8vm3jkg",
"title": "Marketing"
}
]
}
]
}
I have tagview in my mobile screen so user can select multiple subcategory at a same time by select deselect so if i choose 2 subcategory from Art and 2 from Business then expected post payload should be like below
{
"data": [
{
"category": "c8kr0cv012vtr8vm3iug",
"subcategories": [
"c8kr7nv012vtr8vm3l8g",
"c8kr7nv012vtr8vm3lag"
]
},
{
"category": "c8kr0cv012vtr8vm3iqg",
"subcategories": [
"c8kr3d7012vtr8vm3jjg",
"c8kr3d7012vtr8vm3jj0"
]
}
]
}
So my code is like below
const tempDefaultPayload = dataPayload.map(x => {
if (x.category) {
x.subcategories?.push(subcategory);
if (userData?.userInterests?.map(v => v.category.documentId === category)) {
const arrayNewData: any = [];
const newData: any = userData?.userInterests?.map(i =>
i.subcategories?.map(k => {
arrayNewData.push(k?.documentId);
return k?.documentId;
}),
);
x.subcategories?.push(...arrayNewData);
}
return x;
}
return x;
})
When I run above code payload is not passing correct
[
{
"category": "c8kr0cv012vtr8vm3iug",
"subcategories": [
"c8kr7nv012vtr8vm3l8g",
"c8kr7nv012vtr8vm3lag",
"c8kr3d7012vtr8vm3jjg",
"c8kr3d7012vtr8vm3jj0"
]
},
{
"category": "c8kr0cv012vtr8vm3iqg",
"subcategories": [
"c8kr7nv012vtr8vm3l8g",
"c8kr7nv012vtr8vm3lag",
"c8kr3d7012vtr8vm3jjg",
"c8kr3d7012vtr8vm3jj0"
]
}
]
It is passing all selected subcategory in both array any idea how can I solve this ?
If you have the selected tag ids in the array selectedTags and your json as a variable called data:
const tempDefaultPayload = {
data: data.data.map(x => {
"category": x.category.documentId,
"subcategories": x.subcategories.map(subcat =>
subcat.documentId).filter(item => selectedTags.includes(item))
})
}
Playground example

Delete all JSON keys nested having specific name

I want to delete all occurances of keynames like etag,formattedType and metadata in the object using dynamic iteration of whole object
var myjson {
"etag": "%EiIBAgMFBgcICQoLDA0ODxATFBUWGSEiIyQlJicuNTc9Pj9AGgECIdgxQTUREdTBneFMzZz0=",
"names": [{
"unstructuredName": "Natalie Victor",
"displayNameLastFirst": "Victor, Natalie",
"familyName": "Victor",
"displayName": "Natalie Victor",
"givenName": "Natalie",
"metadata": {
"source": {
"id": "c8de0718a7c3458",
"type": "CONTACT"
},
"primary": true
}
}],
"photos": [{
"metadata": {
"primary": true,
"source": {
"id": "c8de0718a7c3458",
"type": "CONTACT"
}
},
"url": "https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAdAA/V8BNOaftJmdYPfvspCwKr2nuTmSEuXTHowCLcDEAEiGQoBThD___________8BGKjbxPr______wE/s100/photo.jpg",
"default": true
}],
"memberships": [{
"metadata": {
"source": {
"type": "CONTACT",
"id": "c8de0718a7c3458"
}
},
"contactGroupMembership": {
"contactGroupId": "6a68e3a408126601",
"contactGroupResourceName": "contactGroups/6a68e3a408126601"
}
}, {
"contactGroupMembership": {
"contactGroupId": "myContacts",
"contactGroupResourceName": "contactGroups/myContacts"
},
"metadata": {
"source": {
"id": "c8de0718a7c3458",
"type": "CONTACT"
}
}
}],
"phoneNumbers": [{
"value": "6767674765",
"formattedType": "Home",
"canonicalForm": "+916767674765",
"metadata": {
"primary": true,
"source": {
"id": "c8de0718a7c3458",
"type": "CONTACT"
}
},
"type": "home"
}],
"emailAddresses": [{
"type": "home",
"formattedType": "Home",
"value": "nati_a_j#hotmail.com",
"metadata": {
"source": {
"id": "c8de0718a7c3458",
"type": "CONTACT"
},
"primary": true
}
}],
"biographies": [{
"contentType": "TEXT_PLAIN",
"value": "Email: ssww#gmail.com\nName.Last: Victor\nName.First: Natalie\nPhone: 6767674765",
"metadata": {
"primary": true,
"source": {
"id": "c8de0718a7c3458",
"type": "CONTACT"
}
}
}],
"resourceName": "people/c904625878430659672"
}
I only know to use delete key by names such as
delete myjson.etag
delete myjson.names[0].metadata
How do I iterate the complete json since some of the json has arrays and nested structures which are not known in advance.
Hence a remove_keys(myjson, ["etag","memberships","formattedType","metadata"]) should render a result
var myjson {
"names": [{
"unstructuredName": "Natalie Victor",
"displayNameLastFirst": "Victor, Natalie",
"familyName": "Victor",
"displayName": "Natalie Victor",
"givenName": "Natalie",
}],
"photos": [{
"url": "https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAdAA/V8BNOaftJmdYPfvspCwKr2nuTmSEuXTHowCLcDEAEiGQoBThD___________8BGKjbxPr______wE/s100/photo.jpg",
"default": true
}],
"phoneNumbers": [{
"value": "6767674765",
"canonicalForm": "+916767674765",
"type": "home"
}],
"emailAddresses": [{
"type": "home",
"value": "nati_a_j#hotmail.com",
}],
"biographies": [{
"contentType": "TEXT_PLAIN",
"value": "Email: ssww#gmail.com\nName.Last: Victor\nName.First: Natalie\nPhone: 6767674765",
}],
"resourceName": "people/c904625878430659672"
}
You need a recursive function for this task:
function filter(obj: any, list: string[]) {
if (obj && typeof obj === 'object') {
for (let item in obj) {
if (list.includes(item)) {
delete obj[item];
} else {
if (Array.isArray(obj[item])) {
for (let el of obj[item]) {
filter(el, list);
}
} else {
filter(obj[item], list);
}
}
}
}
return obj;
}
// example usage:
let a = {b: 5, c: 6, d: { a: 1, b: 2}}
filter(a, ['b']);
console.log(a);
Conversely, it may be faster in some interpreters to rebuild the object, rather than delete keys.
function removeKeys(obj, keys) {
if (Array.isArray(obj))
return obj.map(v => removeKeys(v, keys))
else if (typeof obj == "object" && obj != null) {
const _obj = {}
Object.keys(obj).forEach(k => {
if(!keys.includes(k)) _obj[k] = removeKeys(obj[k], keys)
})
return _obj
}
else
return obj
}
console.log(removeKeys(myjson, ["etag","memberships","formattedType","metadata"]))
this recursive function will solve your problem
var myjson = {
"etag":"%EiIBAgMFBgcICQoLDA0ODxATFBUWGSEiIyQlJicuNTc9Pj9AGgECIdgxQTUREdTBneFMzZz0=",
"names":[
{
"unstructuredName":"Natalie Victor",
"displayNameLastFirst":"Victor, Natalie",
"familyName":"Victor",
"displayName":"Natalie Victor",
"givenName":"Natalie",
"metadata":{
"source":{
"id":"c8de0718a7c3458",
"type":"CONTACT"
},
"primary":true
}
}
],
"photos":[
{
"metadata":{
"primary":true,
"source":{
"id":"c8de0718a7c3458",
"type":"CONTACT"
}
},
"url":"https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAdAA/V8BNOaftJmdYPfvspCwKr2nuTmSEuXTHowCLcDEAEiGQoBThD___________8BGKjbxPr______wE/s100/photo.jpg",
"default":true
}
],
"memberships":[
{
"metadata":{
"source":{
"type":"CONTACT",
"id":"c8de0718a7c3458"
}
},
"contactGroupMembership":{
"contactGroupId":"6a68e3a408126601",
"contactGroupResourceName":"contactGroups/6a68e3a408126601"
}
},
{
"contactGroupMembership":{
"contactGroupId":"myContacts",
"contactGroupResourceName":"contactGroups/myContacts"
},
"metadata":{
"source":{
"id":"c8de0718a7c3458",
"type":"CONTACT"
}
}
}
],
"phoneNumbers":[
{
"value":"6767674765",
"formattedType":"Home",
"canonicalForm":"+916767674765",
"metadata":{
"primary":true,
"source":{
"id":"c8de0718a7c3458",
"type":"CONTACT"
}
},
"type":"home"
}
],
"emailAddresses":[
{
"type":"home",
"formattedType":"Home",
"value":"nati_a_j#hotmail.com",
"metadata":{
"source":{
"id":"c8de0718a7c3458",
"type":"CONTACT"
},
"primary":true
}
}
],
"biographies":[
{
"contentType":"TEXT_PLAIN",
"value":"Email: ssww#gmail.com\nName.Last: Victor\nName.First: Natalie\nPhone: 6767674765",
"metadata":{
"primary":true,
"source":{
"id":"c8de0718a7c3458",
"type":"CONTACT"
}
}
}
],
"resourceName":"people/c904625878430659672"
}
function removeKeys(obj,keys){
if(Array.isArray(obj)){
obj.forEach(innerObj=>{
removeKeys(innerObj,keys)
})
}else{
keys.forEach(k=>{
delete obj[k];
})
Object.keys(obj).forEach(key=>{
if(typeof obj[key]=='object'){
removeKeys(obj[key],keys)
}
})
}
}
removeKeys(myjson, ["etag","memberships","formattedType","metadata"])
console.log(myjson);

transforming json using recursive function

I'm trying to transform this JSON into array so that I can simply list them as key-value pairs in html. The JSON has nested properties which I want to retain but I want to stringify only those objects that contain "units" and "value". All others should be listed as children items. Please help figure what I'm doing wrong.
Here's the json input:
{
"clusterName": "ml6.engrlab.com-cluster",
"statusProperties": {
"loadProperties": {
"loadDetail": {
"restoreWriteLoad": {
"value": 0,
"units": "sec/sec"
},
},
"totalLoad": {
"value": 0.0825921967625618,
"units": "sec/sec"
}
},
"secure": {
"value": false,
"units": "bool"
},
"statusDetail": {
"licenseKeyOption": [
{
"value": "conversion",
"units": "enum"
},
{
"value": "failover",
"units": "enum"
}
],
"connectPort": 7999,
"softwareVersion": {
"value": 9000100,
"units": "quantity"
}
},
"rateProperties": {
"rateDetail": {
"largeReadRate": {
"value": 0,
"units": "MB/sec"
}
},
"totalRate": {
"value": 67.2446365356445,
"units": "MB/sec"
}
},
"online": {
"value": true,
"units": "bool"
},
"cacheProperties": {
"cacheDetail": {
"tripleCachePartitions": {
"tripleCachePartition": [
{
"partitionSize": 768,
"partitionBusy": 0,
"partitionUsed": 0,
"partitionFree": 100
}
]
}
}
}
}
}
my code
function isNested(obj) {
if(!obj) return false;
let propArry = Object.keys(obj)
for(let i=0; i<propArry.length; i++){
if(obj[propArry[0]].constructor.name === 'Object') return true
}
return false;
}
function getKeyValueAsChildren(obj) {
let vals = [];
for(let key in obj) {
if(obj.hasOwnProperty(key)){
vals.push({key:key, value: obj[key]})
}
}
return vals
}
function valueAsString(obj) {
if(typeof obj !== 'object') return obj;
return `${obj['value']} ${obj['units']}`
}
function getChildren(key, obj) {
if(Object.keys(obj).sort().toString() === "units,value"){
return {key: key, value: valueAsString(obj)}
} else {
return {key: key, children: getKeyValueAsChildren(obj) }
}
}
function getValues(properties, values = []) {
for(let key in properties) {
if(properties.hasOwnProperty(key)) {
let value = properties[key]
if(typeof value !== 'object') {
values.push({key: key, value: value})
} else if(Array.isArray(value)){
let children = []
value.map(v => {
children.push(getChildren(key, v))
})
values.push({key: `${key}List`, children: children})
}
else if(value.constructor.name === 'Object' && isNested(value)){
// I THINK THE MAIN PROBLEM IS HERE
let keys = Object.keys(value)
let children = [];
keys.forEach(key => {
children.push({key: key, children: getValues(value[key])})
})
values.push({key: key, children: children})
}
else {
values.push(getChildren(key, value))
}
}
}
return values
}
getValues(hostProperties)
this returns
[
{
"key": "clusterName",
"value": "ml6.engrlab.com-cluster"
},
{
"key": "statusProperties",
"children": [
{
"key": "loadProperties",
"children": [
{
"key": "loadDetail",
"children": [
{
"key": "restoreWriteLoad",
"children": [
{
"key": "value",
"value": 0
},
{
"key": "units",
"value": "sec/sec"
}
]
}
]
},
{
"key": "totalLoad",
"value": "0.0825921967625618 sec/sec"
}
]
},
{
"key": "secure",
"children": [
{
"key": "value",
"value": false
},
{
"key": "units",
"value": "bool"
}
]
},
{
"key": "statusDetail",
"children": [
{
"key": "licenseKeyOptionList",
"children": [
{
"key": "licenseKeyOption",
"value": "conversion enum"
},
{
"key": "licenseKeyOption",
"value": "failover enum"
}
]
},
{
"key": "connectPort",
"value": 7999
},
]
},
{
"key": "rateProperties",
"children": [
{
"key": "rateDetail",
"children": [
{
"key": "largeReadRate",
"children": [
{
"key": "value",
"value": 0
},
{
"key": "units",
"value": "MB/sec"
}
]
}
]
},
{
"key": "totalRate",
"value": "67.2446365356445 MB/sec"
}
]
},
{
"key": "online",
"children": [
{
"key": "value",
"value": true
},
{
"key": "units",
"value": "bool"
}
]
},
{
"key": "cacheProperties",
"children": [
{
"key": "cacheDetail",
"children": [
{
"key": "tripleCachePartitions",
"children": [
{
"key": "tripleCachePartitionList",
"children": [
{
"key": "tripleCachePartition",
"children": [
{
"key": "partitionSize",
"value": 768
},
{
"key": "partitionBusy",
"value": 0
},
{
"key": "partitionUsed",
"value": 0
},
{
"key": "partitionFree",
"value": 100
}
]
}
]
}
]
}
]
}
]
}
]
}
]
but I need this
[
{
"key": "clusterName",
"value": "ml6.engrlab.com-cluster"
},
{
"key": "statusProperties",
"children": [
{
"key": "loadProperties",
"children": [
{
"key": "loadDetail",
"children": [
{
"key": "restoreWriteLoad",
"value": "0 sec/sec"
}
]
},
{
"key": "totalLoad",
"value": "0.0825921967625618 sec/sec"
}
]
},
{
"key": "secure",
"value": "false bool"
},
{
"key": "statusDetail",
"children": [
{
"key": "licenseKeyOptionList",
"children": [
{
"key": "licenseKeyOption",
"value": "conversion enum"
},
{
"key": "licenseKeyOption",
"value": "failover enum"
}
]
},
{
"key": "connectPort",
"value": 7999
}
]
},
{
"key": "rateProperties",
"children": [
{
"key": "rateDetail",
"children": [
{
"key": "largeReadRate",
"value": "0 MB/sec"
}
]
},
{
"key": "totalRate",
"value": "67.2446365356445 MB/sec"
}
]
},
{
"key": "online",
"value": "true bool"
},
{
"key": "cacheProperties",
"children": [
{
"key": "cacheDetail",
"children": [
{
"key": "tripleCachePartitions",
"children": [
{
"key": "tripleCachePartitionList",
"children": [
{
"key": "tripleCachePartition",
"children": [
{
"key": "partitionSize",
"value": 768
},
{
"key": "partitionBusy",
"value": 0
},
{
"key": "partitionUsed",
"value": 0
},
{
"key": "partitionFree",
"value": 100
}
]
}
]
}
]
}
]
}
]
}
]
}
]
You might have to run more tests, as what you require seems quite arbitrary, but I believe this function does what you are looking for. It works in a similar way to yours, by simply recursing the tree, and checking for object types, and if the special case is matched.
function toKeyValue(obj) {
return Object.keys(obj).map(k => {
var value = obj[k]
var key = k
var valueName = 'children'
if(Array.isArray(value)){
key = k + 'List'
value = value.map(toKeyValue)
}else if(value !== null && typeof value === 'object'){
// check for special case
if(Object.keys(value).sort().toString() === "units,value"){
value = value.value + ' ' + value.units
valueName = 'value'
}else{
value = toKeyValue(value)
}
}else{
valueName = 'value'
}
return {
key: key,
[valueName]: value
}
})
}
Fiddle here

Building new JSON from existing one

I want to build an new JSON from existing one. The source has sections and rubrics that I no longer need for a listing. The new object called 'items' should have an array of the items.
The final JSON should be sorted by attribute 'name' and look like
{
"items": [
{
"id": 10000006,
"name": "Boah"
},
{
"id": 10000013,
"name": "Gut"
},
{
"id": 10000003,
"name": "Ipsum"
},
{
"id": 10000001,
"name": "Lorem"
},
{
"id": 10000005,
"name": "Lorum"
},
{
"id": 10000004,
"name": "Name"
},
{
"id": 10000002,
"name": "Stet"
}
]
}
For building the new JSON I get this source:
{
"sections": [
{
"name": "FooBar",
"rubrics": [
{
"name": "Foo",
"items": [
{
"id": 10000001,
"name": "Lorem"
},
{
"id": 10000002,
"name": "Stet"
},
{
"id": 10000003,
"name": "Ipsum"
}
]
},
{
"name": "Bar",
"items": [
{
"id": 10000004,
"name": "Name"
},
{
"id": 10000005,
"name": "Lorum"
},
{
"id": 10000006,
"name": "Boah"
}
]
}
]
},
{
"name": "BlahBloob",
"rubrics": [
{
"name": "Bla",
"items": [
{
"id": 10000013,
"name": "Gut"
}
]
},
{
"name": "Bloob",
"items": [
{
"id": 10000014,
"name": "Name"
},
{
"id": 10000015,
"name": "Lorem"
}
]
}
]
}
]
}
What do you think? How can I do this with plain JavaScript or maybe TypeScript?
Thanks for reading and have time for my question. And thanks for reply in advance.
Here you go. You just need to iterate over each rubric of each section of your source to get the items. At the end, sort your list of items by items, and you're done.
This example uses ES6 syntax, but it's easy to convert it to ES5 if needed.
function extractItems(source) {
const items = [];
for (const section of source.sections) {
for (const rubric of section.rubrics) {
items.push(...rubric.items);
}
}
items.sort((a, b) => a.name.localeCompare(b.name));
return { items };
}
A more functional approach use map and reduce to pick the rubrics and merge them.
data.sections
.map(section => section.rubrics) // get rubrics
.reduce((a, b) => a.concat(b)) // merge rubrics
.map(rubric => rubric.items) // get items from each rubric
.reduce((a, b) => a.concat(b)) // merge items
.sort((a, b) => a.name.localeCompare(b.name)); // sort
function(oldObj) {
var newObj = {
"items": []
};
oldObj.sections.forEach(function(section) {
section.rubrics.forEach(function(rubric) {
rubric.items.forEach(function(item) {
newObj.items.push(item);
});
});
});
newObj.items = newObj.items.sort(function(a, b) {
if (a.name < b.name) { return -1; }
if (a.name > b.name) { return 1; }
return 0;
});
return newObj;
}
And simply use JSON.parse() and JSON.stringify() to convert JSON to and from objects.
It might help you
var data ={
"sections": [
{
"name": "FooBar",
"rubrics": [{"name": "Foo", "items": [{"id": 10000001,"name": "Lorem"}, {"id": 10000002,"name": "Stet"}, {"id": 10000003,"name": "Ipsum"}]
}, {
"name": "Bar",
"items": [{
"id": 10000004,
"name": "Name"
}, {
"id": 10000005,
"name": "Lorum"
}, {
"id": 10000006,
"name": "Boah"
}]
}]
}, {
"name": "BlahBloob",
"rubrics": [{
"name": "Bla",
"items": [{
"id": 10000013,
"name": "Gut"
}]
}, {
"name": "Bloob",
"items": [{
"id": 10000014,
"name": "Name"
}, {
"id": 10000015,
"name": "Lorem"
}]
}]
}]
};
var itemObj = {};
var itemArr = [];
var sections = data.sections;
for(var i=0;i<sections.length;i++)
{
for(var j=0;j<sections[i].rubrics.length;j++){
for(var k=0;k<sections[i].rubrics[j].items.length;k++){
var itemObj;
itemObj['id'] = sections[i].rubrics[j].items[k].id;
itemObj['name'] = sections[i].rubrics[j].items[k].name;
itemArr.push(itemObj);
}
}
}
var finalObj = {"items":itemArr};
console.log(finalObj);
JSFiddle

Categories

Resources