Cannot read property of length undefined - javascript

I'm using a dexi.io robot to automate extraction from permit databases. The robot will accept custom javascript to parse the incoming JSON object.
This code appears to work in some cases - correctly parsing the incoming JSON - but fails in almost every circumstance. The error is cannot read property of length undefined.
Here's the test api that works: https://services.odata.org/V4/TripPinService/People
Here's the code:
var people = JSON.parse(json).value;
var arr = [];
function getCountry(member) {
try {
return member.fields.name;
} catch(err) {
return "";
}
}
for (i = 0; i < people.length; i++) {
var member = people[i];
var obj =
{
"name": member.name,
"Country": getCountry(member),
"alias": member.alias
};
arr.push(obj);
}
return arr;

Check your first line where is "json".I think you didn't defined a json file from which you are getting data.

Not sure exactly what you are doing to fetch the response, but I was able to get this working pretty easily:
fetch("https://services.odata.org/V4/TripPinService/People")
.then(response => response.json())
.then(data => {
var people = data.value;
var arr = [];
function getCountry(member) {
try {
return member.AddressInfo[0].City.CountryRegion;
} catch(err) {
return "Country Info Not Available";
}
}
for (i = 0; i < people.length; i++) {
var member = people[i];
var obj =
{
"name": member.FirstName,
"Country": getCountry(member),
"alias": member.alias
};
arr.push(obj);
}
console.log(arr);
});
Maybe this will give you some ideas.

I have checked the json from the given url. So, in your code the properties like 'member.name', 'member.alias', 'member.fields.name' doesn't exist.
Try using the exact property names from the json:
{
"#odata.context": "http://services.odata.org/V4/TripPinService/$metadata#People",
"#odata.nextLink": "https://services.odata.org/V4/TripPinService/People?%24skiptoken=8",
"value": [
{
"#odata.id": "http://services.odata.org/V4/TripPinService/People('russellwhyte')",
"#odata.etag": "W/\"08D817F8EC7DAC16\"",
"#odata.editLink": "http://services.odata.org/V4/TripPinService/People('russellwhyte')",
"UserName": "russellwhyte",
"FirstName": "Russell",
"LastName": "Whyte",
"Emails": [
"Russell#example.com",
"Russell#contoso.com"
],
"AddressInfo": [
{
"Address": "187 Suffolk Ln.",
"City": {
"CountryRegion": "United States",
"Name": "Boise",
"Region": "ID"
}
}
],
"Gender": "Male",
"Concurrency": 637285705159912400
}
]
}
What I am trying to say is that use the names exactly in json like 'member.UserName', 'member.AddressInfo[0].Name' etc.

Related

How to render key value pairs from object react

This is object data that I have stored in my this.state.profile from an API request.
What I need to do know is render the values from the keys to the web broswer. I am trying with the code below which does not work. Also how do I render the objects within side this object? This is all so confusing :(
{
"localizedLastName": "King",
"lastName": {
"localized": {
"en_US": "King"
},
"preferredLocale": {
"country": "US",
"language": "en"
}
},
"firstName": {
"localized": {
"en_US": "Benn"
},
"preferredLocale": {
"country": "US",
"language": "en"
}
},
"profilePicture": {
"displayImage": "urn:li:digitalmediaAsset:C5603AQGjLGZPOyRBBA"
},
"id": "fm0B3D6y3I",
"localizedFirstName": "Benn"
}
How I am trying to render it:
const { profile } = this.state;
const profileList = Object.keys(profile).map((key,value)=>{
return (
<div>{key}{value.toString()}</div>
);
})
{ profileList }
try:
return (
{Object.entries(profile).map(([key,value]) => {
<div>{key} : {value.toString()}</div>
})}
)
the iteration needs to happen inside of the return.
You could build up your object outside your render call like below and just render it (elements).
var elements = [];
for (var prop in this.state.profile) {
elements.push(<div>{prop} : {this.state.profile[prop].toString()}</div>)
}
If it's not working my guess would be your state isn't initialised or your target js version doesn't support Object.entries
First of all, you need to deal with nested objects:
{
...
"firstName": {
"localized": {
"en_US": "Benn"
},
"preferredLocale": {
"country": "US",
"language": "en"
}
}...
}
If you try to render the value on the key firstName, you will get a object as value, and React can't render objects as elements.
And if you call toString() on it, you will get [Object object] as value.
To solve this, you gonna need some recursion:
const objToString = obj => {
let result = [];
Object.keys(key => {
if(typeof obj[key] === 'object'){
let children = (<div>{key} : {objToString(obj[key])}</div>)
result.push(children)
} else
result.push(<div>{key} : {obj[key]}</div>)
})
}
...
const profileList = objToString(profile)
This should give you this something like:
...
<div>firstName:
<div>localized:
<div>en_US: Benn</div>
</div>
</div>
...

Getting a array as a result when the result should be an Map?

I am trying to use MAP into node.js program and I am getting final result however its in array but I need in map. I have write some code to use map but its not working as expected.
Please find below program
function CreateProduceMVPRateAsset(data, callback) {
var ProducePRICE = {};
var MVPPRICE = [];
var MVPPRICE_BS = {};
var MVPPRICE_LB = {};
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = new FileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
console.log('Data', data);
console.log('Username', data.username);
var PRODUCENAME = data.PRODUCE;
var COUNTRY = data.COUNTRY;
var STATE = data.STATE;
var MVPRATES = data.MVPRATES;
console.log('MVPRATERATE', MVPRATES);
// here I need help
const MVPRATE = new Map(MVPRATES);
for (const [k, v] of MVPRATE.entries()) {
console.log('Inside map', k, v);
MVPPRICE = v.RATE; // should go in MVPPRICE
var Value = MVPPRICE[0].value; // want to get first element value from MVPPRICE array
console.log('Value', Value);
var value_lb = Value / 40;
console.log('value_lb', value_lb);
value_lb = Number(value_lb.toFixed(4));
console.log('If the value of BS provided controller come here');
MVPPRICE_LB.Value = value_lb;
MVPPRICE_LB.QuantityUnit = 'LB';
MVPPRICE_LB.uidisplay = false;
MVPPRICE_LB.CurrencyUnit = 'USD';
MVPPRICE.push(MVPPRICE_LB);
ProducePRICE.MVPPRICE = MVPPRICE;
ProducePRICE.PRODUCENAME = PRODUCENAME;
ProducePRICE.STATE = STATE;
ProducePRICE.COUNTRY = COUNTRY;
console.log('ProducePRICE', ProducePRICE); // whatever result getting it should be map however getting in array.
}
}
JSON structure which I am sending using postman
{
"username": "admin2",
"PRODUCE": "Apple",
"STATE": "MI",
"COUNTRY": "US",
"MVPRATES": {
"fuji": {
"VARIETY": "fuji",
"RATE": [
{
"UNIT": "Bussel",
"CURRENCY": "USD",
"VALUE": 10.25,
"UIDISPLAY": true
}
]
},
"gala": {
"VARIETY": "gala",
"RATE": [
{
"UNIT": "Bussel",
"CURRENCY": "USD",
"VALUE": 10.25,
"UIDISPLAY": true
}
]
}
}
}
Output which I am getting:
#SudhakarRS is right, you're getting your MAP back, you're just getting your values in an array for MVPRATE, and it almost looks like that was your intention, seeing you push here:
MVPPRICE.push(MVPPRICE_LB);
I mentioned in the comments, but I think what's happening is the Map doesn't apply recursively, so when it sees MVPPRICE, it's treating your value array, as the value instead of part of the map.
I think what you're trying to do can be solved by this:
MVPPRICE.concat(MVPPRICE_LB);
ProducePRICE.MVPPRICE = new Map(MVPPRICE)

How to count the amount of times JSON data has a key with a specific value in Jquery?

My question deals with the following JSON data :
{"matches":[
{
"country":"USA",
"postcode":"9011"
},
{
"country":"USA",
"postcode":"9010"
},
{
"country":"UK",
"postcode":"BB3"
}
]}
Could anyone tell me how to retrieve the amount of times where country = USA ?
In the current case, the desired output is : 2.
I have been searching for hours how to do this, but have been unable to find the solution.
Thanks in advance for your help.
Regards,
Just loop through and count. You can use reduce() for this and increment the count when the value matches what you want.
let o = {"matches":[{"country":"USA", "postcode":"9011"},{"country":"USA", "postcode":"9010"},{"country":"UK", "postcode":"BB3"}]}
let num_usa = o.matches.reduce((count, el) => {
if (el.country === 'USA') count++
return count
}, 0)
console.log(num_usa)
I thank the users that have replied for the help they have provided.
For some reason, I could process the JSON when it was written in a variable (as in the replies), but not when the same JSON was returned from an ajax process.
My issue has been finally solved by switching to XML.
<matches>
<result country = "USA" postcode = "9011" />
<result country = "USA" postcode = "9011" />
<result country = "UK" postcode = "BB3" />
</matches>
var countcountry = $(xml_result).find('result[country="usa"]').length;
Returns : 2
using reduce is definitely my suggestion. In case you're interested to count other country, you can do it this way below:
const response = {
"matches": [{
"country": "USA",
"postcode": "9011"
}, {
"country": "USA",
"postcode": "9010"
}, {
"country": "UK",
"postcode": "BB3"
}]
}
const countryCount = response.matches.reduce((acc, match) => {
const country = match.country;
if (!acc[country]) {
acc[country] = 1;
} else {
acc[country]++;
}
return acc;
}, {});
// print USA and UK
console.log(countryCount.USA);
console.log(countryCount.UK);
Try this :
var jsonObj = {"matches":[
{
"country":"USA",
"postcode":"9011"
},
{
"country":"USA",
"postcode":"9010"
},
{
"country":"UK",
"postcode":"BB3"
}
]};
var count = 0;
for (var i in jsonObj.matches) {
(jsonObj.matches[i].country == 'USA') ? count = count+1 : 0;
}
console.log("Country count with USA :", count);
Using Array#filter() and length of resultant is fairly simple for this use case
let data = {"matches":[{"country":"USA", "postcode":"9011"},{"country":"USA", "postcode":"9010"},{"country":"UK", "postcode":"BB3"}]}
let us_count = data.matches.filter(({country:c}) => c === 'USA').length
console.log(us_count)

Array of key-value pair JSON object parsing

Hi I have have a given array of JSON object in a file:
file.json:
[
{
"id": "xccdf_saphana.content_profile_test1",
"info": {
"applicable_platforms": ["SUSE", "RHEL", "SUSE FOR SAP APP"],
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type":"System"
}
},
{
"id": "xccdf_saphana.content_profile_test2",
"info": {
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type":"System"
}
}
]
Below is the way I am reading it.
var obj = JSON.parse(fs.readFileSync(file.json, 'utf8')); // read the file
myID = "xccdf_saphana.content_profile_test2";
var myInfo = getInfobyID(myID);
function getInfobyID(myID) {
// Got messed up, tried changing JSON structure multiple time, so that I can easily parse it.
for(var i=0; i < obj.length; ++i) {
if(obj[i].id == myID)
return obj[i].info;
}
}
Is their any way I can optimize it, as I will be recursively searching for multiple myID later.
Turn your json into an object rather than an array. Then you can make quick lookups.
let hash = obj.reduce((agg, e) => {
agg[e.id] = e;
return agg;
}, {});
let value = hash["xccdf_saphana.content_profile_test2"].info;
The naming 'obj' is a bit confusing here since it is actually an array of objects (from the JSON file).
Try something like:
var myArrOfObj = JSON.parse(fs.readFileSync(file.json, 'utf8'));
var myID = "xccdf_saphana.content_profile_test2";
var myInfo = getInfobyID(myID);
function getInfobyID(myID){
var matchingObj = myArrOfObj.find((obj) => obj.id === myID);
// Fallback to empty string since there might be no match.
return (matchingObj) ? matchingObj.info : '';
}
You can use Array.reduce to convert your array into an object with key as id and value as info.
Now you can just return the object[id] and get the info without iterating everytime.
var json = [{
"id": "xccdf_saphana.content_profile_test1",
"info": {
"applicable_platforms": ["SUSE", "RHEL", "SUSE FOR SAP APP"],
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type": "System"
}
},
{
"id": "xccdf_saphana.content_profile_test2",
"info": {
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type": "System"
}
}
];
var data = json.reduce((acc, curr) => {
acc[curr.id] = curr.info;
return acc;
}, {});
function getInfobyID(data, id) {
return data[id];
}
console.log(getInfobyID(data, "xccdf_saphana.content_profile_test2"));
Based on this requirement:
Is their any way I can optimize it...
You may want to store the ID value as the key of a map, and any info related to it as the value. This way, whenever you are searching, if you already have the ID yo can access the data for that ID in constant time, or O(1), as opposed to linear time, or O(n).
This is the only way to speed up your search without more complex data structures, but it comes with one caveat which is that you no longer have a list. You will be using a map.
Change this:
[
{
"id": "xccdf_saphana.content_profile_test1",
"info": {
"applicable_platforms": ["SUSE","RHEL","SUSE FOR SAP APP"],
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type":"System" }
},
{
"id": "xccdf_saphana.content_profile_test2",
"info": {
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type":"System" }
}
]
To this:
{
"xccdf_saphana.content_profile_test1": {
"applicable_platforms": ["SUSE","RHEL","SUSE FOR SAP APP"],
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type":"System"
},
"xccdf_saphana.content_profile_test2": {
"applicable_workloads": "SalesPromo",
"applicable_compliance": "CIS",
"type":"System"
}
}
Now you don't need any loops. You just have one object, with each member of the object representing a different item.
In your code, you can simply do obj[myId] and you will either get undefined if it doesn't exist, or you will get an object of the matching result.
This is the fastest a search could possibly be, but again it requires a map-like data structure and not a list.
If you absolutely must use a list, the only real optimization to be made is as follows:
Cache your list length, so you do not have to calculate it on each iteration of the loop
Your new getInfobyID could look like this:
function getInfobyID(myID){
var len = obj.length;
for (var i=0; i < len; ++i){
if( obj[i].id == myID)
return obj[i].info;
}
}

How to parse all JSON strings in a JavaScript object

I have 1 JavaScript object like this:
result = {
"status": "success",
"message": "Get successful!",
"data": {
"name":"Hello world",
"school": {
"name":"LHP",
"address":"HCM"
},
"class": "[{\"text\":\"Math\",\"code\":\"math124\"},{\"text\":\"Libra\",\"code\":\"libra124\"}]",
"student": "{\"time_range\":{\"type\":\"select\",\"text\":\"Today\",\"value\":[{\"code\":\"in_today\",\"text\":\"In Today\"}]}}"
}
}
So I have to parse class and student separately:
result.data.class = JSON.parse(result.data.class);
result.data.student = JSON.parse(result.data.student);
Is there other way to parse the whole result variable or make this step shorter/better?
Thanks
You could loop through the data property's children and parse them.
for (var i = 0; i < Object.keys(result.data).length; i++) {
try {
result.data[Object.keys(result.data)[i]] = JSON.parse(result.data[Object.keys(result.data)[i]]);
} catch (error) {} // it's already JSON
}
But I'd only do that if you're sure you'll only ever have to deal with stringified JSON in the data property of your object.

Categories