Can not iterate through Javascript Object - javascript

I have the following object (return from Insomnia)
[
{
"field": 10.5,
"this_is_a_bool": 1,
"name": "",
"data": "2018-05-22T03:00:00.000Z",
"field2": null
},
{
"field": 5.3,
"this_is_a_bool": 0,
"name": "Slim Shady",
"data": "2020-01-22T04:45:00.000Z",
"field2": null
}
]
The problem is that I can't iterate over those "set of values" so I can edit them.
To do something like this:
for (const val in myObj) {
if (val.field2 === null) {
val.field1 = 'flag - ' + val.field1
}
}
What I've tried:
for (const val in myObj)
for (const val of myObj)
const [key,value] of Object.entries(myObj)
Errors: Sometimes it says myObj is not iterable and sometimes the code is just ignored.

Why don't you use simple .map():
const src = [{"field":10.5,"this_is_a_bool":1,"name":"","data":"2018-05-22T03:00:00.000Z","field2":null},{"field":5.3,"this_is_a_bool":0,"name":"Slim Shady","data":"2020-01-22T04:45:00.000Z","field2":null}],
result = src.map(({field, field2, ...rest}) => ({
field: field2 === null ? `flag-${field}` : field,
field2,
...rest
}))
console.log(result)
.as-console-wrapper{min-height:100%;}

or... if you still want using for loop...
(in your sample val is key)
var myObj = [
{
"field": 10.5,
"this_is_a_bool": 1,
"name": "",
"data": "2018-05-22T03:00:00.000Z",
"field2": null
},
{
"field": 5.3,
"this_is_a_bool": 0,
"name": "Slim Shady",
"data": "2020-01-22T04:45:00.000Z",
"field2": null
}
];
for (const val in myObj) {
if (myObj[val].field2 === null){
myObj[val].field = 'flag - ' + myObj[val].field;
}
}
console.log(myObj);

Related

JS: How to parse a nested JSON?

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()

Renaming keys in an object using reduce method in JS

Following is the object in which I want to replace countryID with value, countryName with label.
In the same object I am having localLanguages Array in which I am trying to rename language with label and languageCode with value.
array -
var obj = [{
"countryID": "CON1010",
"countryName": "Poland",
"countryCode": "pl",
"localLanguages": [{
"language": "English",
"languageCode": "en"
},
{
"language": "Polish",
"languageCode": "en"
}
]
},
{
"countryID": "CON1011",
"countryName": "UK",
"countryCode": "uk",
"localLanguages": [{
"language": "English",
"languageCode": "en"
}]
}
];
Transformed to -
var obj = [{
"value": "CON1010",
"label": "Poland",
"countryCode": "pl",
"localLanguages": [{
"label": "English",
"value": "en"
},
{
"label": "Polish",
"value": "en"
}
]
},
{
"value": "CON1011",
"label": "UK",
"countryCode": "uk",
"localLanguages": [{
"label": "English",
"value": "en"
}]
}
];
Code -
arr.map(x => {
var newObj = Object.keys(x).reduce((obj, key) => {
if (key !== 'countryID') {
obj[key] = x[key]
}
if (key === 'countryID') {
obj.value = x.countryID;
}
}, {})
console.log(newObj);
return newObj;
})
Here is a solution with es6 Destructuring and map:
const arr = [{"countryID":"CON1010","countryName":"Poland","countryCode":"pl","localLanguages":[{"language":"English","languageCode":"en"},{"language":"Polish","languageCode":"en"}]},{"countryID":"CON1011","countryName":"UK","countryCode":"uk","localLanguages":[{"language":"English","languageCode":"en"}]}];
const result = arr.map(item => {
let localLanguages = item.localLanguages.map(i => {
const { language: label, languageCode: value, ...rest } = i;
return { label, value, ...rest };
});
const { countryID: value, countryName: label, ...rest } = item;
return { value, label, ...rest, localLanguages };
});
console.log(result)
Use Array.map() to convert the outer objects, and another map to convert the localLanguages:
const arr = [{"countryID":"CON1010","countryName":"Poland","countryCode":"pl","localLanguages":[{"language":"English","languageCode":"en"},{"language":"Polish","languageCode":"en"}]},{"countryID":"CON1011","countryName":"UK","countryCode":"uk","localLanguages":[{"language":"English","languageCode":"en"}]}];
const result = arr.map(o => ({
value: o.countryID,
label: o.countryName,
countryCode: o.countryCode,
localLanguages: o.localLanguages.map(l => ({
value: l.languageCode,
label: l.language
}))
}));
console.log(result)
You have forgotten to return obj value in the reduce function
var newObj = Object.keys(x).reduce( (obj, key) => {
if(key !== 'countryID') {
obj[key] = x[key]
}
if(key === 'countryID') {
obj.value = x.countryID;
}
}, {})
Here the function to change the keys. Use it with every element of you arrayrecursively, but check the type of every element
function changeKeys(obj) {
const rename = {
'countryID': 'value',
'countryName': 'label',
'language': 'label',
'languageCode': 'value'
}
return Object.keys(obj)
.reduce(
(acc, rec) => {
if (typeof rename[rec] !== 'undefined') {
return {...acc, [rename[rec]]: obj[rec]}
}
return {...acc, [rec]: obj[rec]}
}, {}
)
}

filter array of object on multi conditions

I have this array
const d = [{
"type": "price",
"value": {
"min": 0,
"max": 170
}
}, {
"type": "name",
"value": {}
}, {
"type": "volume",
"options": [1,2]
}]
I want to filter if value doesn't have a value or options is an empty array. So I did
d.filter(o => o.value || o.options)
I expect type:name is gone but why it's still there?
I also tried lodash
d.filter(o => !isEmpty(o.value) || !isEmpty(o.options))
doesn't work as expected?
{} and [] are truthy values
console.log(Boolean([]))
console.log(Boolean({}))
You can check for length in case of array, in case of object you can get keys or values or entries and check it's length
const d = [{"type": "price","value": {"min": 0,"max": 170}}, {"type": "name","value": {}}, {"type": "volume","options": [1,2]}]
let op = d.filter(o => ( Object.values(o.value || {}) || (o.options || [] )).length)
console.log(op)
With lodash, you can use _.reject() with _.isEmpty() to remove items that have an empty value object and an empty options array:
const arr = [{"type": "price","value": {"min": 0,"max": 170}}, {"type": "name","value": {}}, {"type": "volume","options": [1,2]}]
const result = _.reject(arr, o => _.isEmpty(o.value) && _.isEmpty(o.options))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
With lodash/fp you can easily generate a function that extracts the value and the options, iterates them with _.every() and return true (should be removed) if both are empty:
const { reject, flow, props, every, isEmpty } = _
const fn = reject(flow(props(['value', 'options']), every(isEmpty)))
const arr = [{"type": "price","value": {"min": 0,"max": 170}}, {"type": "name","value": {}}, {"type": "volume","options": [1,2]}]
const result = fn(arr)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
Here is my solution.
const d = [{
"type": "price",
"value": {
"min": 0,
"max": 170
}
}, {
"type": "name",
"value": {}
}, {
"type": "volume",
"options": [1,2]
}]
function notEmpty(n){
return (!!n ? typeof n === 'object' ? Array.isArray(n) ? !!n.length : !!Object.keys(n).length : true : false);
}
console.log(d.filter(o => notEmpty(o.value) || notEmpty(o.options)));
Hope will help you.
Give the custom filter callback where you check for any entry in values property and options property.
const d = [
{
"type": "price",
"value": {
"min": 0,
"max": 170
}
},
{
"type": "name",
"value": {}
},
{
"type": "volume",
"options": [1,2]
}
];
function doesHaveValuesAndOptions(obj) {
const valueEntries = obj.value ? Object.entries(obj.value) : [],
options = obj.options || [];
if (!valueEntries.length && !options.length)
return false;
else if (valueEntries.length || options.length)
return true;
return false;
}
const res = d.filter(doesHaveValuesAndOptions);
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>

Push object keys and its values to array

I have an object like this:
{
"id": 23,
"name": "Jacob",
"link": {
"rel": "self",
"link": "www.abc.com"
},
"company":{
"data":{
"id": 1,
"ref": 324
}
}
I want to store each key with its value to an array in javascript or typescript like this
[["id":23], ["name":"Jacob"], ["link":{......, ......}]] and so on
I am doing this so that I can append an ID for each.
My best guess I would loop through the array and append an ID/a flag for each element, which I don't know how to do as well.... how to address this issue ? thanks
var arr = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var innerObj = {};
innerObj[prop] = obj[prop];
arr.push(innerObj)
}
}
console.log(arr);
here is demo https://plnkr.co/edit/9PxisCVrhxlurHJYyeIB?p=preview
p.forEach( function (country) {
country.forEach( function (entry) {
entry.push( {"value" : 'Greece', "synonyms" : 'GR'});
});
});
you can try to use experimental Object.entries:
let obj = {
"id": 23,
"name": "Jacob",
"link": {
"rel": "self",
"link": "www.abc.com"
},
"company":{
"data":{
"id": 1,
"ref": 324
}
}};
console.log(Object.entries(obj).map(item => ({[item[0]]:item[1]})));
for unsupported browsers you can use polyfill: https://github.com/es-shims/Object.entries
You could use an iterative/recursive approach with the object and their nested parts. It works for any depths.
function getKeyValue(object) {
return Object.keys(object).reduce(function (result, key) {
return result.concat(
object[key] && typeof object[key] === 'object' ?
getKeyValue(object[key]) :
[[key, object[key]]]
);
}, []);
}
var data = { id: 23, name: "Jacob", link: { rel: "self", link: "www.abc.com" }, company: { data: { id: 1, ref: 324 } } };
console.log(getKeyValue(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use the Object.keys method to get an array of the keys, then use the Array#map method to return a new array containing individual objects for each property.
This ES6 one-liner should do it:
const splitObject = o => Object.keys(o).map(e => ({ [e]: o[e] }));
Or in ES5:
function splitObject(o) {
return Object.keys(o).map(function(e) {
return Object.defineProperty({}, e, {
value: o[e],
enumerable: true
});
});
}
var res = [];
_.transform( {
"id": 23,
"name": "Jacob",
"link": {
"rel": "self",
"link": "www.abc.com"
},
"company": {
"data": {
"id": 1,
"ref": 324
}
}
}, function(result, value, key) {
res.push(key +':'+value);
}, {});
You can use underscore
Supported in all major browser, including IE11
Object.entries() gives you exactly this.
const obj = {
id: 23,
name: 'Jacob',
link: {
rel: 'self',
link: 'www.abc.com'
},
company: {
data: {
id: 1,
ref: 324
}
}
};
Object.entries(obj);
// output:
[
[
"id",
23
],
[
"name",
"Jacob"
],
[
"link",
{
"rel": "self",
"link": "www.abc.com"
}
],
[
"company",
{
"data": {
"id": 1,
"ref": 324
}
}
]
]
var obj=[{"Name":ABC,"Count":123},{"Name":XYZ,"Count":456}];
var arr = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var innerObj = {};
innerObj[0] = obj[prop];
arr.push(innerObj[0]);
}
}
/* Here above exmple innerobj index set to 0 then we will get same data into arr if u not menstion then arr will conatins arr[0] our result.
then we need to call first record obj arr[0][0] like this*/
const foo = { "bar": "foobar", "foo": "foobar" }
Object.entries(foo)
should result in:
[["bar", "foobar"], ["foo", "foobar"]]
maybe there's a function to pass to convert all commas to colons
Here's the documentation
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries

Categories