Related
I have a JSON file with the following format:
{
"Afghanistan": [
{
"date": "2020-1-22",
"confirmed": 0,
"deaths": 0,
"recovered": 0
},
{
"date": "2020-1-23",
"confirmed": 0,
"deaths": 0,
"recovered": 0
},
...
],
"Albania": [
{
"date": "2020-1-22",
"confirmed": 0,
"deaths": 0,
"recovered": 0
},
{
"date": "2020-1-23",
"confirmed": 0,
"deaths": 0,
"recovered": 0
},
...
],
...
}
My goal is to extract data in a way so as to get the date, confirmed, deaths and recovered of each country. The problem I am having is finding a way to do this for all countries as opposed to just one.
For instance, if I write the line data.Afghanistan[0].confirmed; //data is a variable i stored the JSON object in, to get info for Afghanistan, I would need to write the same line for Albania as well and for all other countries separately.
I know there a way I can do this for all counties in a more efficient way but I can't seem to find it. Can someone please help me out? Any help would be appreciated. Thanks
Use Object.keys(). For example, Object.keys(yourJSONObject) will return an array of your keys, i.e. ["Afghanistan", "Albania"]. You can use this to iterate over each key/value in your JSON.
I think this would work:
const countries = Object.keys(data);
const confirmedDeathsByCountry = countries.map(country => data[country][0].confirmed);
You can loop through the arrays inside each country in your JSON file like so:
for (var key in data) {
//key is the country ie. "Afghanistan"
var records = data[key]; //array of records
for (var index in records) {
var record = records[index]; //object with the properties
var date = record.date;
var confirmed = record.confirmed;
var deaths = record.deaths;
var recovered = record.recovered;
}
}
I have the following JSON in a file called census.json:
{
"areas": [
"UnitedStates", [{
"STATEORREGION": "United States",
"1910POPULATION": 92228531,
"1920POPULATION": 106021568,
"1930POPULATION": 123202660,
"1940POPULATION": 132165129,
"1950POPULATION": 151325798,
"1960POPULATION": 179323175,
"1970POPULATION": 203211926,
"1980POPULATION": 226545805,
"1990POPULATION": 248709873,
"2000POPULATION": 281421906,
"2010POPULATION": 308745538,
"1910CHANGE": 21,
"1920CHANGE": 15,
"1930CHANGE": 16.2,
"1940CHANGE": 7.3,
"1950CHANGE": 14.5,
"1960CHANGE": 18.5,
"1970CHANGE": 13.3,
"1980CHANGE": 11.5,
"1990CHANGE": 9.8,
"2000CHANGE": 13.2,
"2010CHANGE": 9.7
}],
"Alabama", [{
"STATEORREGION": "Alabama",
"1910POPULATION": 2138093,
"1920POPULATION": 2348174,
"1930POPULATION": 2646248,
"1940POPULATION": 2832961,
"1950POPULATION": 3061743,
"1960POPULATION": 3266740,
"1970POPULATION": 3444165,
"1980POPULATION": 3893888,
"1990POPULATION": 4040587,
"2000POPULATION": 4447100,
"2010POPULATION": 4779736,
"1910CHANGE": 16.9,
"1920CHANGE": 9.8,
"1930CHANGE": 12.7,
"1940CHANGE": 7.1,
"1950CHANGE": 8.1,
"1960CHANGE": 6.7,
"1970CHANGE": 5.4,
"1980CHANGE": 13.1,
"1990CHANGE": 3.8,
"2000CHANGE": 10.1,
"2010CHANGE": 7.5
}],
"Alaska", [{
"STATEORREGION": "Alaska",
"1910POPULATION": 64356,
"1920POPULATION": 55036,
"1930POPULATION": 59278,
"1940POPULATION": 72524,
"1950POPULATION": 128643,
"1960POPULATION": 226167,
"1970POPULATION": 300382,
"1980POPULATION": 401851,
"1990POPULATION": 550043,
"2000POPULATION": 626932,
"2010POPULATION": 710231,
"1910CHANGE": 1.2,
"1920CHANGE": -14.5,
"1930CHANGE": 7.7,
"1940CHANGE": 22.3,
"1950CHANGE": 77.4,
"1960CHANGE": 75.8,
"1970CHANGE": 32.8,
"1980CHANGE": 33.8,
"1990CHANGE": 36.9,
"2000CHANGE": 14,
"2010CHANGE": 13.3
}], ]
}
I am trying to access the different values stored in the array using the following:
$.getJSON("../data/census.json", function (json) {
var censusData = json;
console.log(censusData.areas);
});
This logs all the states to the console as an object, so I then tried to go down another level with:
$.getJSON("../data/census.json", function (json) {
var censusData = json;
console.log(censusData.areas.UnitedStates);
});
but this returns "undefined". How can I drill down another level? Ideally I would like to access each states population for a specific year and then assign it to a variable that I can use later.
the pattern here is after each string name we have an array of related information:
so you can convert it to an object like
var _result = {};
for ( var i=0;i<arr.length/2;i++){
_result[arr[i]] = arr[i+1];
}
then you can directly access those information by their string names
like this
censusData.areas.UnitedStates
will return an array after this transformation
There is currently no second level as there are commas instead of colons between the state names and their properties:
"Alaska", [{
"STATEORREGION":"Alaska",
"1910POPULATION":64356,
...
This makes the values "Alaska" and the dictionary of properties adjacent elements in a list. It seems what you want is:
"Alaska": [{
"STATEORREGION":"Alaska",
"1910POPULATION":64356,
...
your json data is invalid try this,
{"areas" : [
"UnitedStates", [{
"STATEORREGION":"United States",
"1910POPULATION":92228531,
"1920POPULATION":106021568,
"1930POPULATION":123202660,
"1940POPULATION":132165129,
"1950POPULATION":151325798,
"1960POPULATION":179323175,
"1970POPULATION":203211926,
"1980POPULATION":226545805,
"1990POPULATION":248709873,
"2000POPULATION":281421906,
"2010POPULATION":308745538,
"1910CHANGE":21,
"1920CHANGE":15,
"1930CHANGE":16.2,
"1940CHANGE":7.3,
"1950CHANGE":14.5,
"1960CHANGE":18.5,
"1970CHANGE":13.3,
"1980CHANGE":11.5,
"1990CHANGE":9.8,
"2000CHANGE":13.2,
"2010CHANGE":9.7
}],
"Alabama", [{
"STATEORREGION":"Alabama",
"1910POPULATION":2138093,
"1920POPULATION":2348174,
"1930POPULATION":2646248,
"1940POPULATION":2832961,
"1950POPULATION":3061743,
"1960POPULATION":3266740,
"1970POPULATION":3444165,
"1980POPULATION":3893888,
"1990POPULATION":4040587,
"2000POPULATION":4447100,
"2010POPULATION":4779736,
"1910CHANGE":16.9,
"1920CHANGE":9.8,
"1930CHANGE":12.7,
"1940CHANGE":7.1,
"1950CHANGE":8.1,
"1960CHANGE":6.7,
"1970CHANGE":5.4,
"1980CHANGE":13.1,
"1990CHANGE":3.8,
"2000CHANGE":10.1,
"2010CHANGE":7.5
}],
"Alaska", [{
"STATEORREGION":"Alaska",
"1910POPULATION":64356,
"1920POPULATION":55036,
"1930POPULATION":59278,
"1940POPULATION":72524,
"1950POPULATION":128643,
"1960POPULATION":226167,
"1970POPULATION":300382,
"1980POPULATION":401851,
"1990POPULATION":550043,
"2000POPULATION":626932,
"2010POPULATION":710231,
"1910CHANGE":1.2,
"1920CHANGE":-14.5,
"1930CHANGE":7.7,
"1940CHANGE":22.3,
"1950CHANGE":77.4,
"1960CHANGE":75.8,
"1970CHANGE":32.8,
"1980CHANGE":33.8,
"1990CHANGE":36.9,
"2000CHANGE":14,
"2010CHANGE":13.3
}]
]
}
So I was able to access the data by changing the structure of the JSON to the following:
{"areas" : [
[{
"STATEORREGION":"United States",
"POPULATION1910":92228531,
"1920POPULATION":106021568,
"1930POPULATION":123202660,
"1940POPULATION":132165129,
"1950POPULATION":151325798,
"1960POPULATION":179323175,
"1970POPULATION":203211926,
"1980POPULATION":226545805,
"1990POPULATION":248709873,
"2000POPULATION":281421906,
"2010POPULATION":308745538,
"1910CHANGE":21,
"1920CHANGE":15,
"1930CHANGE":16.2,
"1940CHANGE":7.3,
"1950CHANGE":14.5,
"1960CHANGE":18.5,
"1970CHANGE":13.3,
"1980CHANGE":11.5,
"1990CHANGE":9.8,
"2000CHANGE":13.2,
"2010CHANGE":9.7
}],
[{
"STATEORREGION":"Alabama",
"1910POPULATION":2138093,
"1920POPULATION":2348174,
"1930POPULATION":2646248,
"1940POPULATION":2832961,
"1950POPULATION":3061743,
"1960POPULATION":3266740,
"1970POPULATION":3444165,
"1980POPULATION":3893888,
"1990POPULATION":4040587,
"2000POPULATION":4447100,
"2010POPULATION":4779736,
"1910CHANGE":16.9,
"1920CHANGE":9.8,
"1930CHANGE":12.7,
"1940CHANGE":7.1,
"1950CHANGE":8.1,
"1960CHANGE":6.7,
"1970CHANGE":5.4,
"1980CHANGE":13.1,
"1990CHANGE":3.8,
"2000CHANGE":10.1,
"2010CHANGE":7.5
}],
[{
"STATEORREGION":"Alaska",
"1910POPULATION":64356,
"1920POPULATION":55036,
"1930POPULATION":59278,
"1940POPULATION":72524,
"1950POPULATION":128643,
"1960POPULATION":226167,
"1970POPULATION":300382,
"1980POPULATION":401851,
"1990POPULATION":550043,
"2000POPULATION":626932,
"2010POPULATION":710231,
"1910CHANGE":1.2,
"1920CHANGE":-14.5,
"1930CHANGE":7.7,
"1940CHANGE":22.3,
"1950CHANGE":77.4,
"1960CHANGE":75.8,
"1970CHANGE":32.8,
"1980CHANGE":33.8,
"1990CHANGE":36.9,
"2000CHANGE":14,
"2010CHANGE":13.3
}]
]
}
Then I used:
$.getJSON( "../data/census.json", function( json ) {
var censusData = json;
console.log(censusData.areas[0][0].POPULATION1910);
});
Also note that I had to change 1910POPULATION to POPULATION1910 in order to access it without getting an error. There may be a better way to do this than changing every key name for every state.
When I want to access the next state I just changed censusData[0][0] to censusData[1][0] and so on and so forth.
The string "United States" is the first element in a list.
The data for The United States is in censusData.areas[1]. The structure of the JSON looks a bit strange.
I'm working with a response from the Webtrends API in Google apps script and I have a JSON/JS object that looks like this:
"data": [
{
"period": "Month",
"start_date": "2013-12",
"end_date": "2013-12",
"attributes": {},
"measures": {
"Visits": 500
},
"SubRows": [
{
"facebook.com": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
},
"google.co.uk": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
},
"newsnow.co.uk": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
},
"No Referrer": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
},
"t.co": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
}
}
]
}
]
What I need to access is the names i.e facebook.com etc... and visit numbers for each of the SubRows.
I'm able to get the visit numbers, but I can't work out how to get the names. Please note the names will change constantly as different sites will send different amounts of traffic each day.
Section of my code at the moment where I get the visit numbers:
for(i in dObj){
var data = dObj[i].SubRows;
var sd = dObj[i].start_date;
var ed = dObj[i].end_date;
if(sd == ed){
var timep = ""+ sd;
}
else{
var timep = ""+ sd + "-" + ed;
}
var subRows = data[0];
Logger.log(subRows);
for(i in subRows){
var row = subRows[i];
var rmeasures = row.measures;
var rvis = rmeasures.Visits;
values = [timep,"",rvis]; //Blank string for where the name of the site would go
}
}
I've tried the following links, but none of them seem to have the answer:
Getting JavaScript object key list
How to access object using dynamic key?
How to access key itself using javascript
How do I access properties of a javascript object if I don't know the names?
I'm just using vanilla google apps script as I don't have any experience with Jquery etc...
Any help would be much appreciated!
I usually use a little helper function that looks like this:
var keyVal = function(o) {
var key = Object.keys(o)[0];
return {"key": key, "val":o[key]};
} ;
This will map an object with a variable key to a key/value object {key:...., val:{}}, which is usually convenient enough to work with.
describe.only ("stack overflow answer", function(){
it ("is should create a key/value pair" , function(){
var res = keyVal( {
"facebook.com": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
}});
res.key.should.equal('facebook.com');
res.val.attributes.should.deep.equal({});
});
Within the loop, the variable i contains the current key. Replacing the empty string with i should give you what you need.
You might also want to look at some of the more functional tools built into Javascript. Some more concise code might also be more explicit:
data.map(function(datum) {
var timep = datum.start_date == datum.end_date ? datum.end_date :
(data.start_date + "-" + datum.end_date);
return datum.SubRows.map(function(subRow) {
return Object.keys(subRow).map(function(key) {
return [timep, key, subRow[key].measures.Visits];
});
});
});
would return an object something like this:
[
[
[
["2013-12", "facebook.com", 100],
["2013-12", "google.co.uk", 100],
["2013-12", "newsnow.co.uk", 100],
["2013-12", "No Referrer", 100],
["2013-12", "t.co", 100 ]
]
]
]
This just uses map and Object.keys to simplify some of what you're doing with explicit loops.
I'm trying to get my head around Javascript array functions. I have a nested array like this, where every row covers the same time period:
[{
"category": "fruit",
"variety": "apple",
"data": [{
"day": 1,
"units": 2
}, {"day": 2,
"units": 4
}]
},{
"category": "fruit",
"variety": "orange",
"data": [{
"day": 1,
"units": 3
}, {"day": 2,
"units": 5
}]
},{
"category": "veg",
"variety": "tomato",
"data": [{
"day": 1,
"units": 4
}, {"day": 2,
"units": 2
}]
}]
I would like to sum the units by day by category, to get an array like this:
[{
"category": "fruit",
"data": [{
"day": 1,
"units": 5
}, {"day": 2,
"units": 9
}]
},{
"category": "veg",
"data": [{
"day": 1,
"units": 4
}, {"day": 2,
"units": 2
}]
}]
I've been tackling this through long looping if statements, and making a bit of a hash of it. Can you see an elegant way to solve this?
Many thanks!
The solution is pretty obvious: Loop through the array, and store the data in a key-value pair. Then, loop through the has, and construct the resulting array using Array.prototype.map. Finally, if you want a nicely formatted JSON-string, use JSON.stringify(result, null, 4);, where 4 is the number of spaced for pretty formatting.
Demo: http://jsfiddle.net/jde6S/
var list = [ ... ];
var hash = {};
for (var i=0; i<list.length; i++) {
var obj = list[i];
// This part makes sure that hash looks like {fruit:[], veg: []}
var hashObjCat = hash[obj.category];
if (!hashObjCat) {
hashObjCat = hash[obj.category] = {};
}
// This part populates the hash hashObjCat with day-unit pairs
for (var j=0; j<obj.data.length; j++) {
var data = obj.data[j];
if (hashObjCat[data.day]) hashObjCat[data.day] += data.units;
else hashObjCat[data.day] = data.units;
}
}
// Now, we hash looks like {fruit: {1:5, 2:9} }
// Construct desired object
var result = Object.keys(hash).map(function(category) {
// Initial object
var obj = {category: category, data:[]};
var dayData = Object.keys(hash[category]);
// This part adds day+units dicts to the data array
for (var i=0; i<dayData.length; i++) {
var day = dayData[i];
var units = hash[category][day];
obj.data.push({day: day, units: units});
}
return obj;
});
// Test:
console.log(JSON.stringify(result, null, 4));
reduce the array to an object (See #RobW's answer on how to do that with loops):
var data = [...] // your input
// Iterate the data with reduce...
var sumsbycategory = data.reduce(function(map, fruit) {
var cat = fruit.category;
// set an property to an object, iterating the days array...
map[cat] = fruit.data.reduce(function(sums, day) {
var d = day.day;
// set or update the units for this day
sums[d] = (sums[d] || 0) + day.units;
return sums; // into the next iteration
}, map[cat] || {}) // ...passing in the already existing map for this cat or a new one
return map; // into the next iteration
}, {}); // ...passing in an empty object
Now we have the following format:
{"fruit":{"1":5,"2":9},"veg":{"1":4,"2":2}}
...which I think is much easier to handle, but lets build your array:
var result = []; // init array
for (var cat in sumsbycategory) { // loop over categories
var data = []; // init array
// add category object:
result.push({category:cat, data:data});
for (var day in sumsbycategory[cat]) // loop over days in category
// add day object
data.push({day:day, units:sumsbycategory[cat][day]});
}
But, wait! An object has no order, and it could happen that day2 comes before days1 in the result array (which might break your appplication?) So, you could use map on the keys of that object which also can be sorted before, to generate the array in one clean-looking expression:
var result = Object.keys(sumsbycategory).map(function(cat) {
return {
category: cat,
data: Object.keys(sumsbycategory[cat])
.sort(function numbercompare(a,b){ return a-b; })
.map(function(day) {
return {
day: day,
units: sumsbycategory[cat][day]
};
})
};
});
result:
[{
"category": "fruit",
"data": [{"day":"1","units":5},{"day":"2","units":9}]
},{
"category": "veg",
"data": [{"day":"1","units":4},{"day":"2","units":2}]
}]
(Demo at jsfiddle.net)
If you're willing to grab some external code and use it to essentially re-index your structure you could probably do something. I know the old dojo data api was a mess to work with, but could allow something like what you seem to be asking.
Personally I'd stick with loops, just keep your variable names readable. Also remember the object literals can be addressed as either an array/hash syntax x[y] or dot syntax x.y
I have a online JSON file that looks something like this:
[
{
"j": 0,
"i": 0,
"DepartureTime": "\/Date(1331667480000+0100)\/",
"ArrivalTime": "\/Date(1331668860000+0100)\/",
"Remarks": [],
"TravelStages": [
{
"ID": 0,
"DepartureStop": {
"WalkingDistance": 0,
"ArrivalTime": null,
"AlightingAllowed": false,
"DepartureTime": null,
"BoardingAllowed": false,
"RealTimeStop": true,
"Rank": 0,
"Lines": null,
"StopPoints": [
{
"ID": 1,
"Name": "1",
"X": 608127,
"Y": 6645778
}
],
"Zone": "1",
"X": 608133,
"Y": 6645768,
"ID": 2300500,
"Name": "Visperud (i Solheimvn)",
"District": "Lørenskog",
"Type": 0,
"Stops": [],
"ShortName": "VIS"
}]
What I want is the grab out the DepartureTime and ArrivalTime, I've seen some examples on how to parse the flickr JSON. But I can't figure out how I can parse this. I also want to store the departureTime and arrivalTime in two separate variables since the content of this two is a time measured in milliseconds since 1970. Can somebody give me a hint on how a can do this, am totally new to Javascript/JSON
Do you have jQuery in your project? If so, you can easily parse the JSON string like this
var obj = $.parseJSON(theJsonText);
alert(obj.DepartureTime);
If not, I suggest including the JSON library (link) and using that.
You can try something like this, assuming that your json file is in jsonfile.json
$.getJSON('jsonfile.json', function(data){
alert("Departure Time: "+ data.DepartureTime);
alert("Arrival Time: "+ data.ArrivalTime);
});
http://api.jquery.com/jQuery.getJSON/
$.getJSON('http://your.domain.example/path/to/file.json', function(data) {
departure_time=data.DepartureTime;
arrival_time=data.ArrivalTime;
do_something_with(departure_time,arrival_time);
});
then do_something_with(str,str) would be called with the strings "\/Date(1331667480000+0100)\/" and "\/Date(1331668860000+0100)\/" (in your example).
you'll still have to convert the dates to numbers, e.g. by running:
parsed_date=new Date(parseInt(input_string.substr(7)));
//substr(7) cuts after "\/Date(", and parseInt ignores ")\/"
//but I don't know how it handles "+0100"
Thats an array containing objects, so you should be able to just set some vars equal to the properties of the first index. to use it like an object, it needs to be parsed.. so either eval(thatJson) or $.parseJSON(thatJson) and then iterate through it.
var responses = [
{
"j": 0,
"i": 0,
"DepartureTime": "\/Date(1331667480000+0100)\/",
"ArrivalTime": "\/Date(1331668860000+0100)\/",
"Remarks": [],
...
}];
var dep = responses[0].DepartureTime;
var arr = responses[0].ArrivalTime;
According to JSONLint.com, your string isn't valid JSON. That is, however, a different issue than what your question asks for.
Assuming a valid subset of your string
var a = '[{"j": 0,"i": 0,"DepartureTime": "/Date(1331667480000+0100)/", "ArrivalTime": "/Date(1331668860000+0100)/","Remarks": []}]';
var obj = $.parseJSON(a);
console.log(obj[0].ArrivalTime);