JS: How to parse a nested JSON? - javascript

There is a JSON object:
var items = [{
"item" : "A",
"checked": false,
"info": { "hello": "world" },
"products": []
},
{
"item" : "B",
"checked": true,
"info": { },
"products": [1, 2, 3]
}];
I need to parse each nested object and if there is additional objects, convert them to string.
For example, first object has another object into "info" key. And put the modified JSON Object in a new array.
I have tried like this:
var modifiedObj = [];
items.forEach(function(item) {
//get only values
var val = Object.values(item);
val.forEach(function(el) {
//only if value is an object
if (typeof el === 'object' && !Array.isArray(el)) {
//convert to str
var str = JSON.stringify(el, null, 2);
console.log(str);
}
});
});
It works, but I cannot get how to put the modified JSON in a new array. So my ideal result is:
modifiedObj = [{
"item" : "A",
"checked": false,
"info": "{ 'hello': 'world' }", //String
"products": []
},
{
"item" : "B",
"checked": true,
"info": "{ }", //String
"products": [1, 2, 3]
}];

You can use .map() to iterate over an array and return a new array.
Since the elements of your array are objects, you'll need to use the for...in loop to iterate over the object.
var items = [{
"item": "A",
"checked": false,
"info": {
"hello": "world"
},
"products": []
},
{
"item": "B",
"checked": true,
"info": {},
"products": [1, 2, 3]
}
];
const modObj = items.map(item => {
for (let prop in item) {
if(typeof item[prop] === 'object' && !Array.isArray(item[prop])) {
item[prop] = JSON.stringify(item[prop])
}
}
return item;
})
console.log({ modObj })
PS: I'm not sure which properties you want stringified so I've kept the original if condition in my answer.
Links to read more about for...in and map()

Related

How to loop object and get value from an object

I have a question about how to loop an object in typescript and to get the value that I want.
my object looks like this:
mockdata = {
"subobj1": {
"order": 1
"value": "abc"
},
"subobj2": {
"order": 2
"value": "aaa"
},
...
}
I want to loop this object and only get the subobject, if order == 1
what I expect is to get object
"subobj1": {
"order": 1
"value": "abc"
}
any solutions?
Just loop through the object using for in syntax and find the respective value!
const mockdata = {
"subobj1": {
"order": 1,
"value": "abc"
},
"subobj2": {
"order": 2,
"value": "aaa"
},
}
let output;
for (const property in mockdata) {
if (mockdata[property].order === 1) {
output = {
[property]: mockdata[property]
}
break;
}
}
console.log('result', output);
Here's a pretty slim way to do it. I usually use Object.keys or .entries to all my obj for loops
const arrOfOrderEqualToOne = Object.entries(mockdata).filter(([key, value]) => value.order === 1));
Try this
let mockdata = {
"subobj1": {
"order": 1,
"value": "abc"
},
"subobj2": {
"order": 2,
"value": "aaa"
},
}
let temp;
Object.keys(mockdata).forEach(key=>{
if(mockdata[key].order==1){
temp=mockdata[key]
}
})
console.log(temp)

Find json object by key and replace it with other object from complex/nested json array

I'm trying to find json object by a property/key from a complex/nested json array and replace it with other json object in an angular project.
I have used lodash to find json object by key but the json path of object can be anywhere on json array.
Here is my sample json array:
{
"type": "form",
"title": "title",
"name": "name",
"display": "form",
"path": "path",
"components": [
{
"mask": false,
"tableView": true,
"alwaysEnabled": false,
"label": "",
"rows": [
[
{
"components": [
{
"key": "key1",
"valueProperty": "value",
"selectedKey": "ValueKey"
}
]
}
],
[
{
"components": [
{
"components": [
{
"key": "key2",
"valueProperty": "value",
"selectedKey": "ValueKey"
}
],
"allowMultipleMasks": false,
"showWordCount": false,
"showCharCount": false,
"alwaysEnabled": false,
"type": "textfield",
"input": true,
"widget": {
"type": ""
}
}
]
}
],
[
{
"components": [
{
"labelPosition": "left-left",
"allowMultipleMasks": false,
"showWordCount": false,
"showCharCount": false,
"alwaysEnabled": false,
"input": true,
"widget": {
"type": ""
}
}
]
}
]
],
"header": [],
"numCols": 2
}
]
}
I'm trying to find the entire json object if it contains "selectedkey" property and replace with other object.
Expected Result:
Json object { "key": "key1", "valueProperty": "value", "selectedKey": "ValueKey" } should be replaced with { "key": "key1", "valueProperty": "value", "selectedKey": "ValueKey" }
Note: Json object can appear at n number of times and json path of object can be anywhere in json array.
UPDATE: If you just want to check if that property exists, you can stringify the object and do an includes check, like this:
function containsKey(obj, key) {
return JSON.stringify(obj).includes(key);
}
//OR
function containsKey(obj, key) {
return JSON.stringify(obj).indexOf(key) !== -1;
}
You can use this to replace the whole object with a conditional block:
if (containsKey(obj, 'selectedKey')) {
obj = otherObj;
}
ADDITIONAL SOLUTION: I also adapted my earlier solution that replaced the selectedKey to just check for the key. The advantage of this solution is that the function will return immediately after finding the selectedKey, as opposed to JSON.stringify, which will iterate over every property and value.
function containsKey(obj, targetKey) {
// if the obj is an array, iterate it and call containsKey
if (Array.isArray(obj)) {
for (let i = 0; i < obj.length; i++) {
return containsKey(obj[i], targetKey);
}
} else {
// if it's not an array, it will be an obj
let keys = Object.keys(obj);
let key, value;
// iterate the keys of the object
for (let i = 0; i < keys.length; i++) {
key = keys[i];
value = obj[key];
// if we find the target key, return true
// otherwise, call containsKey on any objects
if (key === targetKey) {
return true;
} else if (typeof value === 'object') {
return containsKey(value, targetKey);
}
}
}
/* by this time we've checked every property of the object,
so we know it does not contain the property or it would
have returned true */
return false;
}

How to remove complete unique value from array [duplicate]

This question already has answers here:
How to remove all duplicates from an array of objects?
(77 answers)
Closed 3 years ago.
How to remove complete record of same object in array please help me this, I am using below funtion but its only remove one value I want remove complete object of same object
var data = [{
"QuestionOid": 1,
"name": "hello",
"label": "world"
}, {
"QuestionOid": 2,
"name": "abc",
"label": "xyz"
}, {
"QuestionOid": 1,
"name": "hello",
"label": "world"
}];
function removeDumplicateValue(myArray) {
var newArray = [];
$.each(myArray, function (key, value) {
var exists = false;
$.each(newArray, function (k, val2) {
if (value.QuestionOid == val2.QuestionOid) { exists = true };
});
if (exists == false && value.QuestionOid != undefined) { newArray.push(value); }
});
return newArray;
}
I want result like this
[{
"QuestionOid": 2,
"name": "abc",
"label": "xyz"
}]
You can use reduce.
var data = [{"QuestionOid": 1,"name": "hello","label": "world"}, {"QuestionOid": 2,"name": "abc","label": "xyz"}, {"QuestionOid": 1,"name": "hello","label": "world"}];
let op = data.reduce((op,inp)=>{
if(op[inp.QuestionOid]){
op[inp.QuestionOid].count++
} else {
op[inp.QuestionOid] = {...inp,count:1}
}
return op
},{})
let final = Object.values(op).reduce((op,{count,...rest})=>{
if(count === 1){
op.push(rest)
}
return op
},[])
console.log(final)
Do with Array#filter.Filter the array matching QuestionOid value equal to 1
var data = [{ "QuestionOid": 1, "name": "hello", "label": "world" }, { "QuestionOid": 2, "name": "abc", "label": "xyz" }, { "QuestionOid": 1, "name": "hello", "label": "world" }]
var res = data.filter((a, b, c) => c.map(i => i.QuestionOid).filter(i => i == a.QuestionOid).length == 1)
console.log(res)

Map object values to keys - Javascript

I have an array from an API call.
var response = {
"data": {
"data": [{
"1": "Arun",
"index": "name"
}, {
"1": 70.78,
"index": "score"
}]
}
}
I connect to a lot of other API's and they return me a similar response but the keys change. Sometimes it might be
var response = {
"data": {
"data": [{
"values": "Harry",
"index": "name"
}, {
"values": 45,
"index": "score"
}]
}
}
var response = {
"data": {
"data": [{
"4": "Richard",
"index": "name"
}, {
"4": 98,
"index": "score"
}]
}
}
I would like to get an array like this.
[
{
name: 'Arun',
score: 70.78
}
]
This is what I did.
var response = {
"data": {
"data": [{
"1": "Arun",
"index": "name"
}, {
"1": 70.78,
"index": "score"
}]
}
}
const result = [];
const mappedData = _.map(response.data.data, (item) => {
return {
[item.index]: item[1]
};
});
const resultObject = _.reduce(mappedData, (result, currentObject) => {
for (const key in currentObject) {
if (currentObject.hasOwnProperty(key)) {
result[key] = currentObject[key];
}
}
return result;
}, {});
result.push(resultObject)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
So instead of hardcoding "1" or "values" in the map function, is there a more universal way to get the key and achieve the same result?
Thanks.
Use reduce rather than map, so you're updating the same object, not creating an array.
And since the property containing the value can vary, I use a loop to look for the first property that isn't named index, and use its value.
var response = {
"data": {
"data": [{
"1": "Arun",
"index": "name"
}, {
"1": 70.78,
"index": "score"
}]
}
}
const mappedData = response.data.data.reduce((acc, item) => {
var value;
// find the property that isn't named "item"
for (var i in item) {
if (i != "index") {
value = item[i];
break;
}
}
acc[item.index] = value;
return acc;
}, {});
console.log(mappedData)
There's no need for lodash for this, the built-in reduce function is fine (but _.reduce will work similarly).
Since you only care about the values of that object and it only has two keys you can do this quite easily in lodash with reduce & fromPairs:
var response = { "data": { "data": [{ "1": "Arun", "index": "name" }, { "1": 70.78, "index": "score" }] } }
const rv = (o) => _.reverse(_.values(o))
const r = _.reduce(response.data.data, (a,c) => _.fromPairs([rv(a), rv(c)]))
console.log(r)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
The same thing converted to ES6 would be:
var response = { "data": { "data": [{ "1": "Arun", "index": "name" }, { "1": 70.78, "index": "score" }] } }
const rv = (o) => Object.values(o).reverse() // reverse values
const fp = (arr) => arr.reduce((r, [k,v]) => (r[k] = v, r), {}) // from pairs
const result = response.data.data.reduce((a,c) => fp([rv(a), rv(c)]))
console.log(result)
The main idea here is to first get the object values in an array form, reverse them so the key & value are in the correct order and then reduce that array via from pairs to create the final object.
The main advantage of this approach is that we never deal with the object keys and only focus on the values which is what you really care about. This way the keys can be any value and it would still not matter.
You could try deleting the key-pair index and using the first value of the resulting object:
const mappedData = _.map(response.data.data, (item) => {
var tempObj = Object.assign({}, item)
var index = tempObj.index;
delete tempObj.index;
var otherData = Object.values(tempObj)[0];
return {
[index]: otherData
};
});
Just modified the #barmar approach. I have used Object.keys to get keys from object. This will remove the any hard-coded dependency.
var response = {
"data": {
"data": [{
"1": "Arun",
"index": "name"
}, {
"1": 70.78,
"index": "score"
}]
}
}
const mappedData = response.data.data.reduce((acc, item,i) => {
var key = Object.keys(item);
acc[item[key[1]]] = item[key[0]]
return acc ;
}, {});
console.log(mappedData)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Iterate an object on a specific order

I have some JSON like this:
{
"a": { "text": "text", "index": 5 },
"b": { "text": "text", "index": 3 },
"c": { "text": "text", "index": 1 },
}
Now I need to interate this object and call a function on every property of the first level (a, b and c), but I have to do it on order using the "index" property, like "c" first, then "b" and last "a".
However I read that I shouldn't use a for in loop:
A for...in loop iterates over the properties of an object in an arbitrary order (see the delete operator for more on why one cannot depend on the seeming orderliness of iteration, at least in a cross-browser setting).
then how I can do this?
Thanks
You could,
Get the properties of the object as an array using Object.keys().
Sort the properties of the object using sort().
Use forEach() to iterate through the sorted items (which is executed in ascending order of the array).
var items = {
"a": {
"text": "text",
"index": 5
},
"b": {
"text": "text",
"index": 3
},
"c": {
"text": "text",
"index": 1,
}
};
Object.keys(items).sort(function(a, b) {
return items[a].index - items[b].index;
}).forEach(doStuff);
function doStuff(key) {
console.log(items[key]);
}
You can use getOwnPropertyNames
let obj = {
"a": { "text": "text", "index": 5 },
"b": { "text": "text", "index": 3 },
"c": { "text": "text", "index": 1 }
};
function test(p) {
console.log(p);
}
Object.getOwnPropertyNames(obj)
.reverse()
.forEach(function(p){
test(obj[p]);
});
You can try the following:
Covert the object to an array with elements in sorted order based on the index.
Than simply forEach() on the sorted properties.
Sort function can be implemented as :
var obj = {
"a": { "text": "text", "index": 5 },
"b": { "text": "text", "index": 3 },
"c": { "text": "text", "index": 1},
}
function sortProperties(obj, sortedBy, isNumericSort, reverse) {
sortedBy = sortedBy || 1; // by default first key
isNumericSort = isNumericSort || false; // by default text sort
reverse = reverse || false; // by default no reverse
var reversed = (reverse) ? -1 : 1;
var sortable = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
sortable.push([key, obj[key]]);
}
}
if (isNumericSort)
sortable.sort(function (a, b) {
return reversed * (a[1][sortedBy] - b[1][sortedBy]);
});
else
sortable.sort(function (a, b) {
var x = a[1][sortedBy].toLowerCase(),
y = b[1][sortedBy].toLowerCase();
return x < y ? reversed * -1 : x > y ? reversed : 0;
});
return sortable; // array in format [ [ key1, val1 ], [ key2, val2 ], ... ]
}
sortProperties(obj, 'index', true, false);
The another solution is store the object keys and reverse it, then iterate with the object keys.
var obj = {
"a": { "text": "text", "index": 5 },
"b": { "text": "text", "index": 3 },
"c": { "text": "text", "index": 1 }
};
var yourFunction = console.log;
var keys = Object.keys(obj);
keys.reverse();
for (var i = 0; i < keys.length; i++) {
yourFunction(obj[keys[i]]);
}
you can also make use of reverse() method of javascript if you want to access the json items in reverse order.
get the array of all the keys of json using Object.keys()
reverse the array using reverse() method
and finally you can make use of javascript forEach() method to work on the items of the json. Sample code is shown below
let obj = {
"a": { "text": "text", "index": 5 },
"b": { "text": "text", "index": 3 },
"c": { "text": "text", "index": 1 },
}
Object.keys(obj)
.reverse()
.forEach(ele => {
console.log(obj[ele]);
});
visit This link to know more about reverse() method
Probably you should use Object.keys to get a list of all the properties, sort that list, then iterate over it.

Categories