How to loop through JSON - javascript

I am trying to loop through this JSON in order to get to the 'name' parameter. The data comes from Microsoft's Bing API. I can pass in coordinates to get the name of a place. I have pasted the response below. as well as my attempt. Please assist.
{
"authenticationResultCode":"ValidCredentials",
"brandLogoUri":"http://dev.virtualearth.net/Branding/logo_powered_by.png",
"copyright":"Copyright © 2018 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
"resourceSets":[
{
"estimatedTotal":1,
"resources":[
{
"__type":"Location:http://schemas.microsoft.com/search/local/ws/rest/v1",
"bbox":[
47.636677282429325,
-122.13698331308882,
47.64440271757068,
-122.12169668691118
],
"name":"1 Microsoft Way, Redmond, WA 98052",
"point":{
"type":"Point",
"coordinates":[
47.64054,
-122.12934
]
},
"address":{
"addressLine":"1 Microsoft Way",
"adminDistrict":"WA",
"adminDistrict2":"King Co.",
"countryRegion":"United States",
"formattedAddress":"1 Microsoft Way, Redmond, WA 98052",
"locality":"Redmond",
"postalCode":"98052"
},
"confidence":"Medium",
"entityType":"Address",
"geocodePoints":[
{
"type":"Point",
"coordinates":[
47.64054,
-122.12934
],
"calculationMethod":"Interpolation",
"usageTypes":[
"Display",
"Route"
]
}
],
"matchCodes":[
"Good"
]
}
]
}
],
"statusCode":200,
"statusDescription":"OK",
"traceId":"089a91ac5b694010884d6a7b7d245718|CH12F221B8|7.7.0.0|CH1AAPBD7C89012"
}
I have tried the following but am getting a length undefined error:
this.http.get('http://dev.virtualearth.net/REST/v1/Locations/'+this.latitude+','+this.longitide+'?o=json&key=AgThwaQToIr5UwjAisaBegjG3qpxBfgFL354mlTxiRPGOrqId8nShnugy40jpebW').subscribe(data => {
this.place = data;
for(var i; i < this.place.resourceSets.length; i++){
this.dataset = this.place.resourceSets[i].resources;
console.log(this.dataset);
}
})
}

I think a big part of your problem is you're using this for your local variable assignments. Ideally you should use let but for backwards compatible browsers you can always use var.
See below, especially the loop, which performs var dataset and also caches the length to the variable n:
var place = {
"authenticationResultCode": "ValidCredentials",
"brandLogoUri": "http://dev.virtualearth.net/Branding/logo_powered_by.png",
"copyright": "Copyright © 2018 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
"resourceSets": [{
"estimatedTotal": 1,
"resources": [{
"__type": "Location:http://schemas.microsoft.com/search/local/ws/rest/v1",
"bbox": [
47.636677282429325, -122.13698331308882,
47.64440271757068, -122.12169668691118
],
"name": "1 Microsoft Way, Redmond, WA 98052",
"point": {
"type": "Point",
"coordinates": [
47.64054, -122.12934
]
},
"address": {
"addressLine": "1 Microsoft Way",
"adminDistrict": "WA",
"adminDistrict2": "King Co.",
"countryRegion": "United States",
"formattedAddress": "1 Microsoft Way, Redmond, WA 98052",
"locality": "Redmond",
"postalCode": "98052"
},
"confidence": "Medium",
"entityType": "Address",
"geocodePoints": [{
"type": "Point",
"coordinates": [
47.64054, -122.12934
],
"calculationMethod": "Interpolation",
"usageTypes": [
"Display",
"Route"
]
}],
"matchCodes": [
"Good"
]
}]
}],
"statusCode": 200,
"statusDescription": "OK",
"traceId": "089a91ac5b694010884d6a7b7d245718|CH12F221B8|7.7.0.0|CH1AAPBD7C89012"
}
for (var i=0,n=place.resourceSets.length; i<n; i++) {
var dataset = place.resourceSets[i].resources;
console.log(dataset);
}

You can try the below code for your question :--
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript">
var text = '{ "data":{"rule":[{"clauses":{ "id":"q", "act":"the", "r":"1","cond":"2"}, "data":{"cond_oper":"7"}},{"clauses":{"id":"qw","act":"thefir","r":"1","cond":"1"},"data":{ "cond_oper":"7"}}]}}';
var obj = JSON.parse(text);
console.log(obj.data.rule.length);
alert(obj.data.rule.length);
//Get the count
// var count = obj.data.rule.length
for(var i=0; i<obj.data.rule.length; i++)
{
alert(obj.data.rule[i].clauses.id);
console.log(obj.data.rule[i].clauses.id)
}
</script>
</head>
<body>
</body>
</html>

Your issue is the var i;, i is not being initialized only declared. Initializing i with = 0 this works fine locally for me using a sample lat/long.
$.get('http://dev.virtualearth.net/REST/v1/Locations/47.640568390488625,-122.1293731033802?o=json&key=AgThwaQToIr5UwjAisaBegjG3qpxBfgFL354mlTxiRPGOrqId8nShnugy40jpebW',function(data){
this.place = data;
console.log(this.place.resourceSets.length);
for(var i = 0; i < this.place.resourceSets.length; i++){
console.log(this.place.resourceSets[0]);
}
});
});

Related

How can I use Watson NLP to analyze Keywords with JS?

I am trying to create a keyword analysis using Watson NLP and JS.
I tried the following code line but the result says ReferrenceError{} and I have no idea on how to make it work..
var keywords=response.result.keywords;
print(keywords);
createElement("h3", "Main keywords of this synopsis");
nbkeywords = 3;
createP("Keywords in this synopsis are:");
createP(keywords[i].text);
}
This is an example of JSON response from the keywords feature of the Watson NLU API (reference):
{
"usage": {
"text_units": 1,
"text_characters": 1536,
"features": 1
},
"keywords": [
{
"text": "curated online courses",
"sentiment": {
"score": 0.792454
},
"relevance": 0.864624,
"emotions": {
"sadness": 0.188625,
"joy": 0.522781,
"fear": 0.12012,
"disgust": 0.103212,
"anger": 0.106669
}
},
{
"text": "free virtual server",
"sentiment": {
"score": 0.664726
},
"relevance": 0.864593,
"emotions": {
"sadness": 0.265225,
"joy": 0.532354,
"fear": 0.07773,
"disgust": 0.090112,
"anger": 0.102242
}
}
],
"language": "en",
"retrieved_url": "https://www.ibm.com/us-en/"
}
Meaning that the "keywords" key in the JSON response is an array containing other JSON objects. To print all keywords you need to loop this array, like shown below with the use of a "for" statement:
var keywords = response.result.keywords;
...
createElement("h3", "Main keywords of this synopsis");
createP("Keywords in this synopsis are:");
var numberOfKeywords = keywords.length;
for (var i = 0; i < numberOfKeywords; i++) {
createP(keywords[i].text);
}
In the official Watson NLU documentation there are Javascript examples that could also help you understand the service API. See https://cloud.ibm.com/apidocs/natural-language-understanding?code=node#keywords.
I hope this answer helps you.

Accessing variables in a JSON?

I'm currently working with the Bing Isochrone Api. I set up my http request in Angular using the HTTPClient. This is the example of the data set I get back:
{
"authenticationResultCode": "ValidCredentials",
"brandLogoUri": "http:\/\/dev.virtualearth.net\/Branding\/logo_powered_by.png",
"copyright": "Copyright © 2018 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
"resourceSets": [{
"estimatedTotal": 1,
"resources": [{
"__type": "IsochroneResponse:http:\/\/schemas.microsoft.com\/search\/local\/ws\/rest\/v1",
"origin": {
"latitude": 47.640068,
"longitude": -122.129858
},
"polygons": [{
"coordinates": [
[
[48.22848, -122.12867],
[48.22613, -122.10625],
[48.229309, -122.08228],
[48.23733, -122.07666],
[48.24474, -122.05325],
[48.24469, -122.0532],
[48.24424, -122.05386],
[48.23119, -122.06654],
[48.22848, -122.12867]
]
]
}]
}]
}],
"statusCode": 200,
"statusDescription": "OK",
"traceId": "4ed97517798141a1b5bb9df40509f190|CO30305304|7.7.0.0|"
}
I can get to the resourceSets with this
this
.http
.get(`http://dev.virtualearth.net/REST/v1/Routes/Isochrones?waypoint=\
${this.testPointlat},${this.testPointlong}&maxTime=15&timeUnit=Minutes\
&dateTime=2017-11-27T18:00:00-08:00&travelMode=Driving\
&key=$$$$$$$$$$$$$
`).subscribe(
(response) => {
this.driveTimeCoords = response.resourceSets;
console.log(this.driveTimeCoords);
const polygons = this.driveTimeCoords.resources.polygons;
console.log(polygons);
}
);
})
So this.driveTimeCoords gives me an array... My attempt after it doesn't work obviously as it says undefined. Would i do a .foreach with an if or something? I'm probably overthinking this. All I want are the coordinates so I can then .map() them into a geojson featuregroup for leaflet.
Thanks!
Edit:
On console.log this.driveTimeCoords I get
[{…}]0: estimatedTotal: 1resources: [{…}]
Your JSON formatting is off: note how resourceSets, resources and polygons are object arrays, meaning you need to call the array's index to access the data, like so:
this.driveTimeCoords = response.resourceSets[0];
console.log(this.driveTimeCoords);
const polygons = this.driveTimeCoords.resources[0].polygons[0];
console.log(polygons);
To fix this issue, your JSON should be formatted like this:
{
"authenticationResultCode": "ValidCredentials",
"brandLogoUri": "http:\/\/dev.virtualearth.net\/Branding\/logo_powered_by.png",
"copyright": "Copyright © 2018 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
"resourceSets": {
"estimatedTotal": 1,
"resources": {
"__type": "IsochroneResponse:http:\/\/schemas.microsoft.com\/search\/local\/ws\/rest\/v1",
"origin": {
"latitude": 47.640068,
"longitude": -122.129858
},
"polygons": {
"coordinates": [
{"latitude": 48.22848, "longitude": -122.12867},
{"latitude": 48.22613, "longitude": -122.10625},
{"latitude": 48.229309, "longitude": -122.08228},
{"latitude": 48.23733, "longitude": -122.07666},
{"latitude": 48.24474, "longitude": -122.05325},
{"latitude": 48.24469, "longitude": -122.0532},
{"latitude": 48.24424, "longitude": -122.05386},
{"latitude": 48.23119, "longitude": -122.06654},
{"latitude": 48.22848, "longitude": -122.12867}
]
}
}
},
"statusCode": 200,
"statusDescription": "OK",
"traceId": "4ed97517798141a1b5bb9df40509f190|CO30305304|7.7.0.0|"
}
I added variable names to the coordinates, for easier comprehension of the data being read.
Judging by your JSON object, it looks like this.driveTimeCoords which is a reference to the resourceSets in your JSON, is an array, which, for every property you seem to want (resource, polygons, coordinates) all successively are arrays as well. Thus, you must do a sequence of nested .map() operations.
Try the following:
var result = this.driveTimeCoords.map((obj)=>{
return obj.resources.map((resource)=>{
return resource.polygon.map((poly)=> poly.coordinates )
})
})
Doing this, makes it so that, if any of those arrays contain multiple references, you'd get them all. Afterwards, you could flatten the array, or simply reference the first one as another guy suggested result[0][0][0]
Seeing as they are arrays, you need to access via thier index:
let json = {
"authenticationResultCode": "ValidCredentials",
"brandLogoUri": "http:\/\/dev.virtualearth.net\/Branding\/logo_powered_by.png",
"copyright": "Copyright © 2018 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
"resourceSets": [{
"estimatedTotal": 1,
"resources": [{
"__type": "IsochroneResponse:http:\/\/schemas.microsoft.com\/search\/local\/ws\/rest\/v1",
"origin": {
"latitude": 47.640068,
"longitude": -122.129858
},
"polygons": [{
"coordinates": [
[
[48.22848, -122.12867],
[48.22613, -122.10625],
[48.229309, -122.08228],
[48.23733, -122.07666],
[48.24474, -122.05325],
[48.24469, -122.0532],
[48.24424, -122.05386],
[48.23119, -122.06654],
[48.22848, -122.12867]
]
]
}]
}]
}],
"statusCode": 200,
"statusDescription": "OK",
"traceId": "4ed97517798141a1b5bb9df40509f190|CO30305304|7.7.0.0|"
}
let polys = json['resourceSets'][0].resources[0].polygons;
let o = document.getElementById('output');
o.innerHTML = JSON.stringify(polys);
<div id="output"></div>
With this formating you can acces coordinate with these paths :
.resourceSets[0].resources[0].polygons[0].coordinates[0][0][0] = 48.22848
.resourceSets[0].resources[0].polygons[0].coordinates[0][0][1] = -122.12867
.resourceSets[0].resources[0].polygons[0].coordinates[0][1][0] = 48.22613
.resourceSets[0].resources[0].polygons[0].coordinates[0][1][1] = -122.10625
.resourceSets[0].resources[0].polygons[0].coordinates[0][2][0] = 48.229309
.resourceSets[0].resources[0].polygons[0].coordinates[0][2][1] = -122.08228
.resourceSets[0].resources[0].polygons[0].coordinates[0][3][0] = 48.23733
.resourceSets[0].resources[0].polygons[0].coordinates[0][3][1] = -122.07666
.resourceSets[0].resources[0].polygons[0].coordinates[0][4][0] = 48.24474
.resourceSets[0].resources[0].polygons[0].coordinates[0][4][1] = -122.05325
.resourceSets[0].resources[0].polygons[0].coordinates[0][5][0] = 48.24469
.resourceSets[0].resources[0].polygons[0].coordinates[0][5][1] = -122.0532
.resourceSets[0].resources[0].polygons[0].coordinates[0][6][0] = 48.24424
.resourceSets[0].resources[0].polygons[0].coordinates[0][6][1] = -122.05386
.resourceSets[0].resources[0].polygons[0].coordinates[0][7][0] = 48.23119
.resourceSets[0].resources[0].polygons[0].coordinates[0][7][1] = -122.06654
.resourceSets[0].resources[0].polygons[0].coordinates[0][8][0] = 48.22848
.resourceSets[0].resources[0].polygons[0].coordinates[0][8][1] = -122.12867

Set filter by partial string in mapbox-gl

My first question here, sorry in advance for any mistake...
I'm developing a mapbox web for my own pleasure, featuring photos taked by myself in a map. Info is loaded in JSON files, with this structure:
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-8.5375900268555,42.881175994873]
},
"properties": {
"title": "Graffiti",
"description": "",
"image": {
"imageSize": [1024, 768], "imageLandscape": 1, "imageUrl": "imgs/gsa_2016_files/20160805173018_OLY_PEP3_P8052307.jpg" },
"icon": {
"iconSize": [96, 73],
"iconUrl": "imgs/gsa_2016_files/thumb_20160805173018_OLY_PEP3_P8052307.jpg"
},
"extended_info": {
"tags": "graffitis,nomada",
"place": "europa,españa,galicia,santiago de compostela"
},
"time": "2016:08:05 17:30:18",
"year": 2016,
"month": 8,
"day": 5
}
}
I work with different JSON files for each map, which are loaded this way:
var map = new mapboxgl.Map({ blah, blah... });
var layerIds = [ '2016' ];
var layerColors = [ 'rgba(255,0,0,1)' ];
function add_sources_to_map()
{
for (var i = 0; i < layerIds.length; i++) {
var id = layerIds[i];
var layerId = layerIdPrefix + id;
var geoJsonFile = 'jsons/'+ id + '.geoJSON';
map.addSource(layerId, { type: 'geojson', data: geoJsonFile });
}
}
Later on I use a function to filter elements by year:
function filterByYear(year) {
var filterFullYear = [ '==', 'year', year];
// Aplica os filtros nas capas
for (var i = 0; i < layerIds.length; i++) {
var id = layerIds[i];
map.setFilter(id, filterFullYear);
}
}
But I would like to do some more filtering, by part of tags or place content. For example, anyone with a "tag" which contains "nomada", or any "place" with "europe". I have tried to do it but failed miserably, although my knowledge of mapbox-gl or even js is limited. Can this be done? Should I change my JSON structure? Can anybody point me to some help?
TIA!
This is not supported in Mapbox-GL-JS. The issue is being tracked here: https://github.com/mapbox/mapbox-gl-js/issues/4698

Iterating over an array of objects?

Here is some sample data that I get from an API:
{
"Document": {
"Placemark": [
{
"name": " V5-MJW",
"address": "Aviation Road, Windhoek, Namibia",
"description": [],
"TimeStamp": {
"when": "2016-05-21T06:12:00-04:00"
},
"styleUrl": "#asset7541",
"Point": {
"coordinates": "17.0829055,-22.598271,743"
}
},
{
"name": "GSatMicro80149",
"address": "Unnamed Road, Lesotho",
"description": [],
"TimeStamp": {
"when": "2016-05-11T04:52:00-04:00"
},
"styleUrl": "#asset7543",
"Point": {
"coordinates": "27.5594894,-29.456703,1659"
}
}
]
}
}
This is my current code that is creating an array:
var flightPlanCoordinates = [];
//data being the returned values from the API.
$.each(data.Document.Placemark, function () {
var location = this.Point.coordinates.split(',');
var loc = {lat: parseFloat(location[1]), lng: parseFloat(location[0])};
flightPlanCoordinates[this.name] == null ? flightPlanCoordinates[this.name] = [] : flightPlanCoordinates[this.name].push(loc);
});
I get a lot of placemarks with the same name, I want to split each placemark with a different name into a different array.
This all works fine until I try to itterate over flightPlanCoordinates, I tried the following:
$.each(flightPlanCoordinates, function(index) {
}
But this does not work, If I log the length of flightPlanCoordinates, it results in 0, yet in Firefox Dev tools I can see the correct values inside of flightPlanCoordinates.
How would I go about doing this? Is there a better way than what I am doing here?
Please change
var flightPlanCoordinates = [];
to
var flightPlanCoordinates = {};
it should be an object, because you set it with properties like flightPlanCoordinates[this.name], where this.name is a string, not an index.

Create collection of objects with Underscore

Basically, I have an array with objects and they would need to be grouped together. It is kinda hard to explain, but it might be easier if I just gave you guys an example.
Result data
[
{
"Category": "Préparé",
"Sandwich": "Martino",
"Ingredient": "Ansjovis",
"Price": 3.1
},
{
"Category": "Préparé",
"Sandwich": "Martino",
"Ingredient": "Tabasco",
"Price": 3.1
},
{
"Category": "Veggie",
"Sandwich": "Gezond",
"Ingredient": "Tomaat",
"Price": 2.5
},
{
"Category": "Veggie",
"Sandwich": "Gezond",
"Ingredient": "Kaas",
"Price": 2.5
}
];
This is a basic example of what my array looks like. I cannot change this structure, it is how our API provides the data.
What I actually need is this structure:
[
{
"CategoryName": "Prépare",
"Sandwiches": [
{
"SandwichName": "Martino",
"Price": 3.1,
"Ingredients": ["Ansjovis", "Tabasco"]
}
]
},
{
"CategoryName": "Veggie",
"Sandwiches": [
{
"SandwichName": "Gezond",
"Price": 2.5,
"Ingredients": ["Tomaat", "Kaas"]
}
]
}
]
I have tried some stuff with Underscore and _.groupBy, _.sortBy, _.countBy
But alas, nothing I have tried actually works. Is this even possible with Underscore (or some other library)?
Also on a sidenote, this example might have some JSON structure mistakes, because I wrote it myself. The data provided by the API has a correct format.
The example only has 2 sandwiches, but in real-time, I'll be retrieving multiple categories with each 20 sandwiches and so on. This is just a minified example, but it provides an idea of what I need.
try this in simple js
var map = {};
results.forEach( function(obj){
map[ obj.CategoryName ] = map[ obj.CategoryName ] || [];
map[ obj.CategoryName ].push( obj );
});
var output = Object.keys(map).map( function(key){
var arr = [];
map[key].forEach(function(obj){
arr.push( {
"SandwichName": obj.SandwichName,
"Price": obj.Price,
"Ingredients": obj.Ingredients
});
});
return { "CategoryName" : key , "Sandwiches" : arr };
});
The following piece of code would do the trick for you:
var data = [...]; // this is your json-data
var result = _.map(_.uniq(_.pluck(data, 'Category')), function(category) {
var sandwiches = _.uniq(_.pluck(_.where(data, { Category: category }), 'Sandwich'));
return {
CategoryName: category,
Sandwiches: _.map(sandwiches, function(sandwich) {
return {
SandwitchName: sandwich,
Price: _.findWhere(data, { Category: category, Sandwich: sandwich }).Price,
Ingredients: _.pluck(_.where(data, { Category: category, Sandwich: sandwich }), 'Ingredient')
};
})
};
});

Categories