Transform data into nested JSON - javascript

I am working with javascript for the first time, and I have an array of around 35000 objects, where each object looks like this:
{city: 'city1', buildingtype: 'buildingtype1', day: 1, hour: 1, energy: 59}
I want to sort this data into a "nested" JSON object, with cities as the first object. For each city, I then need to sort by buildingtype, and for each buildingtype I want an array with the energy, sorted by time.
I have added an image here which might explain it a bit better:
I have begun with something like this
let transformed_data = {}
$:{
datapoints.forEach((d)=> {
if(!(d.city in transformed_data)){
transformed_data[city] = {};
}
}
)
}
Would this be a good way to move forward?
Edit:
Thanks to some nice help this is the solution I found, where I used that the data was already sorted to my advantage.
let transformed_data = {}
$:{
datapoints.forEach((d)=> {
if(!(d.city in transformed_data)){
transformed_data[d.city] = {};
}
if (!(d.buildingtype in transformed_data[d.city])){
transformed_data[d.city][d.buildingtype] = [];
}
transformed_data[d.city][d.buildingtype].push(d.total_heating_energy)
}
)
}
The resulting object can be found here: Final_result

Related

How to combine JS Objects with duplicate key/values

sorry if this is a easy question, I am just having a hard time trying to figure out how I would tackle this problem.
For example, I have 2 Objects as below:
cont oldCar = {
model: 'Honda',
notes: {
id: 1,
timestamp: 2000,
text: 'is old'
}
}
cont oldCar = {
model: 'Toyota',
notes: {
id: 1,
timestamp: 4000,
text: 'is new'
}
}
I want to try and combine the above two objects. I know they have same key's so I wanted to merge the values of each key if they are the same. Such as:
mode: 'Honda / Toyota'
I tried the following:
let merged = {...obj1, ...obj2};
But this will merge both objects but it only retains the values from the right object. I was trying to do a for loop and add check if the key is same in both objects then combine the values together but I keep getting lost and it is hard to visualise. If someone could help me understand how i can create an for loop to start the comparison that would help me in completing the rest.
To do this merge, perhaps you could do some array-reduce, it will also work with a list of unspecific size:
let array = Array(oldCar1,oldCar2)
let result = array.reduce((a,b)=> {
let r = Object.assign({},a)
r.notes = Object.assign({},r.notes)
if (a.model != b.model) {
r["model"] = a.model + " / " + b.model;
}
if (a.notes.text != b.notes.text) {
r.notes.text = a.notes.text + " / " + b.notes.text;
}
// ...
return r;
})
What exactly do you want to achieve? Is it only the merging of model prop or something else?
Do you have more than two objects, is the amount of objects dynamic? If there are only two objects you can do that without any loops.
const merged = {
model: `${firstCar.model} / ${secondCar.model}`,
// etc...
};
But as I said before - if the amount of objects is not constant then you'd need a map that would:
go through each car
try and find a match by ID from other cars
if there's a match return a merged result, if there's no match return the object as it is
Let me know what exactly are your needs here.

Is it efficient to create multiple keys pointing to the same object?

I have an array of countries, where each country have three properties.
const countries = [
{ name: "Poland", alpha: "POL", code: "616" },
{ name: "Hungary", alpha: "HUN", code: "348" },
// and so on...
]
Later on I want to easily access each country by any of these properties.
I was thinking of reducing this array to an object that would have three keys for each country pointing to the very same country object.
Something like this:
const countriesObject = countries.reduce((object, country) => {
const { name, alpha, code } = country;
// Create individual country object
object[name] = { ...country };
// Reference just created country object
object[code] = object[name];
object[alpha] = object[name];
return object;
});
In the end I could access each country object either by its name, code or alpha.
countriesObject["Poland"] // β†’
countriesObject["POL"] // β†’ The same object
countriesObject["616"] // β†’
My question is, would it be considered good practice, or there are some better ways to achieve the same or similar result?
Thank you!
That's fine, as all of those keys, as you correctly noted, will be pointing to the same object. The biggest problem that I see here is that it's easy to reduce readability of the code by using this approach. Let's say we have this fragment:
console.log( countriesObject[id] );
The question is, what is id here? Is it full country name? or just alpha? or code? You might just not care, true, but if you do, consider giving them additional structure:
const countriesObject = countries.reduce((object, country) => {
const { name, alpha, code } = country;
const countryCopy = { ...country };
// it makes sense to place them on the same line to show the intent
object.name[name] = object.code[code] = object.alpha[alpha] = countryCopy;
return object;
}, { name: {}, code: {}, alpha: {} });
Another potential issue is that you won't be able to drop the countries easily from this object; it's not enough to delete just a single key pointing to it, you'll have to go and remove all three. But that doesn't seem to be a big thing here; this looks more like a dictionary.
You can indeed write it like this:
var countries = {[
"poland": {
alpha: "POL", code: "616"
},
"hungary": {
alpha: "HUN", code: "348"
}
]}
Accessing each country like this:
var poland = countries.poland;
This, in turn, produces more readable code:
var alpha = countries.poland.alpha;
instead of
var alpha = countries[0].alpha;
But there is no set preference.
Docs

Is there a way to iterate and display the list of key value pairs of json using Handlebar.js

As Iam new to javascript, I found handleBar.js can be used to template with dynamic data.
I worked on a sample which worked fine and the json structure was simple and straight forward.
(function()
{
var wtsource = $("#some-template").html();
var wtTemplate = Handlebars.compile(wtsource);
var data = { users: [
{url: "index.html", name: "Home" },
{url: "aboutus.html", name: "About Us"},
{url: "contact.html", name: "Contact"}
]};
Handlebars.registerHelper('iter', function(context, options) {
var fn = options.fn, inverse = options.inverse;
var ret = "";
if(context && context.length > 0) {
for(var i=0, j=context.length; i<j; i++) {
ret = ret + fn($.extend({}, context[i], { i: i, iPlus1: i + 1 }));
}
} else {
ret = inverse(this);
}
return ret;
});
var temp=wtTemplate(data);
$("#content").html(temp);
})();
<script id="some-template" type="text/x-handlebars-template">
{{#iter users}}
<li>
{{name}}
</li>
{{/iter}}
</script>
How to iterate a json with the below structure ? Please do suggest the possible way for iterating and creating the template for the below json structure
var newData = { "NEARBY_LIST": {
"100": {
"RestaurantID": 100,
"ParentRestaurantID": 0,
"RestaurantName": "Chennai Tiffin",
"listTime": [{
"startTime": "10:00",
"closeTime": "23:30"
} ]
},
"101": {
"RestaurantID": 101,
"ParentRestaurantID": 0,
"RestaurantName": "Biriyani Factory",
"listTime": [{
"startTime": "11:00",
"closeTime": "22:00"
}]
}
}
};
Accessing the properties of an object has nothing to do with Handlebars. If you dealing with JSON and you wish to access it in general bracket or dot notation, you must first parse the JSON into a JavaScript object using the JSON.parse() function.
After this is done, you may access the properties as follows.
var property = newData['NEARBY_LIST']['100'].RestaurantName; // "Chennai Tiffin"
Here is a fiddle to illustrate.
http://jsfiddle.net/qzm0cygu/2/
I'm not entirely sure what you mean, but if your question is how you can use/read the data in newData, try this:
newData = JSON.parse(newData); //parses the JSON into a JavaScript object
Then access the object like so:
newData.NEARBY_LIST //the object containing the array
newData.NEARBY_LIST[0] //the first item (key "100")
newData.NEARBY_LIST[1] //the second item (key "101")
newData.NEARBY_LIST[0][0] //the first field of the first item (key "RestaurantID", value "100")
newData.NEARBY_LIST[0][2] //the third field of the first item (key "RestaurantName", value "Chennai Tiffin")
newData.NEARBY_LIST[0][3][0] //the first field of the fourth field of the first item (key "startTime", value "11:00")
I hope this was what you were looking for.
EDIT: as Siddharth points out, the above structure does assume you have arrays. If you are not using arrays you can access the properties by using their names as if they're in an associative array (e.g. newData["NEARBY_LIST"]["100"]. The reason I say "properties" and "as if" is because technically JavaScript doesn't support associative arrays. Because they are technically properties you may also access them like newData.NEARBY_LIST (but I don't recommend that in this case as a property name may not start with a number, so you would have to use a mix of the different notations).
On that note, I would recommend using arrays because it makes so many things easier (length checks, for example), and there are practically no downsides.
EDIT2: also, I strongly recommend using the same camelcasing conventions throughout your code. The way you currently have it (with half your properties/variables starting with capitals (e.g. "RestaurantName", "RestaurantID") and the other half being in lowerCamelCase (e.g. "listTime", "startTime")) is just asking for people (you or colleagues) to make mistakes.

Combining JSON Arrays with jQuery

I've spent all morning messing with this now and reading on here, but have found myself going round in circles!
I am trying to draw a chart using the excellent AmCharts Javascript Charts, to show me stock holding as a bar chart and stock turn as a line chart.
I cannot get both sets of data from one query to my database, and cannot use AmCharts StockChart as it is not time based data... therefore, I have two sets of data which need combining with Javascript.
The data is being pulled from a database and returned successfully as JSON arrays similar to this:
SALES DATA:
[{"brandName":"Fender","gearShiftedPerMonth":"35","retailSalesPerMonth":"55"},
{"brandName":"Gibson","gearShiftedPerMonth":"23","retailSalesPerMonth":"43"},
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13"}]
STOCK DATA:
[{"brandName":"Gibson","stockValue":"1234"},
{"brandName":"Fender","stockValue":"975"},
{"brandName":"Epiphone","stockValue":"834"}]
Obviously the actual figures are made up in that example!
Now, what I need to do is to combine those to create this:
COMBINED DATA
[{"brandName":"Fender","gearShiftedPerMonth":"35","retailSalesPerMonth":"55","stockValue":"975"},
{"brandName":"Gibson","gearShiftedPerMonth":"23","retailSalesPerMonth":"43","stockValue":"1234"},
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13","stockValue":"834"}]
What we have there is the Sales Dataset combined with Stock Dataset to add the additional data of stockValue added to the corresponding brandName record.
I have tried using $.extend but I can't figure out how to use it in this situation.
It is perhaps important to note that the data pairs might not necessarily be in the right order, and it is possible, though unlikely, that there might not be a match, so some kind of zeroing error catching must be implemented.
What you'll need to do first is transform the data into two objects, whose properties are the values you want to merge together:
{
"Fender" : {"gearShiftedPerMonth":"35","retailSalesPerMonth":"55"},
"Gibson" : {"gearShiftedPerMonth":"23","retailSalesPerMonth":"43"},
"Epiphone" : {"gearShiftedPerMonth":"10","retailSalesPerMonth":"13"}
}
and
{
"Gibson": {"stockValue":"1234"},
"Fender": { "stockValue":"975"},
"Epiphone": { "stockValue":"834"}
}
Once the transformation is done, you'll have two objects that you can merge using $.extend or other functions.
Update
For large sets, this gives results in nearly linear time:
var salesa = {}, stocka = {};
$.each(sales, function(i, e) {
salesa[e.brandName] = e;
});
$.each(stock, function(i, e) {
stocka[e.brandName] = e;
});
var combine = {};
$.extend(true, combine, salesa, stocka)
More speed can be tweaked if the merging happened during the second transformation callback ($each(stock...) instead of a separate call to $.extend() but it loses some of its obviousness.
I think what's he's trying to do is join the two datasets as if they were tables, joining by the brandName. From what I've been testing jQuery's $.extend() function does not take care of that, but merges objects according to their index in the Object arrays that it receives.
I think the matching of the key would need to be done manually.
stock = [{"brandName":"Fender","gearShiftedPerMonth":"35","retailSalesPerMonth":"55"},
{"brandName":"Gibson","gearShiftedPerMonth":"23","retailSalesPerMonth":"43"},
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13"}];
value = [{"brandName":"Gibson","stockValue":"1234"},
{"brandName":"Fender","stockValue":"975"},
{"brandName":"Epiphone","stockValue":"834"}];
var results = [];
$(stock).each(function(){
datum1 = this;
$(value).each(function() {
datum2 = this;
if(datum1.brandName == datum2.brandName)
results.push($.extend({}, datum1, datum2));
});
});
Which would result in:
[{"brandName":"Fender","gearShiftedPerMonth":"35","retailSalesPerMonth":"55","stockValue":"975"},
{"brandName":"Gibson","gearShiftedPerMonth":"23","retailSalesPerMonth":"43","stockValue":"1234"},
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13","stockValue":"834"}]
Instead of what the use of $.extend() returns:
[{"brandName":"Gibson","gearShiftedPerMonth":"35","retailSalesPerMonth":"55","stockValue":"1234"},
{"brandName":"Fender","gearShiftedPerMonth":"23","retailSalesPerMonth":"43","stockValue":"975"},
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13","stockValue":"834"}]
If your example code reflects reality, then jQuery's $.extend will be the wrong tool for this.
It blindly copies data from one object to another. Notice that the order of your data is not consistent. The SALES DATA has Fender first, while the STOCK DATA has gibson first.
So jQuery's $.extend is mixing the two results. The "gearShifted" and "retailSales" for Fender is ending up with the "brandName" and "stockValue" for Gibson.
What you'll need is to iterate one array, and look up the "brandName" in the other, and then copy over the data you want. You could use $.extend for that part of it if you like...
var sales_data =
[{"brandName":"Fender","gearShiftedPerMonth":"35","retailSalesPerMonth":"55"},
{"brandName":"Gibson","gearShiftedPerMonth":"23","retailSalesPerMonth":"43"},
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13"}]
var stock_data =
[{"brandName":"Gibson","stockValue":"1234"},
{"brandName":"Fender","stockValue":"975"},
{"brandName":"Epiphone","stockValue":"834"}]
var combined = $.map(sales_data, function(obj, i) {
return $.extend({}, obj, $.grep(stock_data, function(stock_obj) {
return obj.brandName === stock_obj.brandName
})[0]);
});
Note that this is not terribly efficient, but unless the data set is enormous, it shouldn't be an issue.
DEMO: http://jsfiddle.net/sDyKx/
RESULT:
[
{
"brandName": "Fender",
"gearShiftedPerMonth": "35",
"retailSalesPerMonth": "55",
"stockValue": "975"
},
{
"brandName": "Gibson",
"gearShiftedPerMonth": "23",
"retailSalesPerMonth": "43",
"stockValue": "1234"
},
{
"brandName": "Epiphone",
"gearShiftedPerMonth": "10",
"retailSalesPerMonth": "13",
"stockValue": "834"
}
]
In vanilla javascript you can do:
var sales = [{"brandName":"Fender","gearShiftedPerMonth":"35","retailSalesPerMonth":"55"},
{"brandName":"Gibson","gearShiftedPerMonth":"23","retailSalesPerMonth":"43"},
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13"}];
var stock = [{"brandName":"Gibson","stockValue":"1234"},
{"brandName":"Fender","stockValue":"975"},
{"brandName":"Epiphone","stockValue":"834"}];
var combined = stock.slice(0);
for (var i = 0; i < stock.length; i++) {
for (var j = 0; j < sales.length; j++) {
if (stock[i].brandName === sales[j].brandName) {
for (var attrname in sales[j]) { combined[i][attrname] = sales[j][attrname]; }
}
}
}
JSON.stringify(combined)
produces
[
{"brandName":"Gibson","stockValue":"1234","gearShiftedPerMonth":"23","retailSalesPerMonth":"43"},
{"brandName":"Fender","stockValue":"975","gearShiftedPerMonth":"35","retailSalesPerMonth":"55"},
{"brandName":"Epiphone","stockValue":"834","gearShiftedPerMonth":"10","retailSalesPerMonth":"13"}
]

Looping to Parse JSON Data

Description and Goal:
Essentially data is constantly generated every 2 minutes into JSON data. What I need to do is retrieve the information from the supplied JSON data. The data will changed constantly. Once the information is parsed it needs to be captured into variables that can be used in other functions.
What I am stuck in is trying to figure out how to create a function with a loop that reassigns all of the data to stored variables that can later be used in functions.
Example information:
var json = {"data":
{"shop":[
{
"carID":"7",
"Garage":"7",
"Mechanic":"Michael Jamison",
"notificationsType":"repair",
"notificationsDesc":"Blown Head gasket and two rail mounts",
"notificationsDate":07/22/2011,
"notificationsTime":"00:02:18"
},
{
"CarID":"8",
"Garage":"7",
"Mechanic":"Tom Bennett",
"notificationsType":"event",
"notifications":"blown engine, 2 tires, and safety inspection",
"notificationsDate":"16 April 2008",
"notificationsTime":"08:26:24"
}
]
}};
function GetInformationToReassign(){
var i;
for(i=0; i<json.data.shop.length; i++)
{
//Then the data is looped, stored into multi-dimensional arrays that can be indexed.
}
}
So the ending result needs to be like this:
shop[0]={7,7,"Michael Jamison",repair,"Blown Head gasket and two rail mounts", 07/22/2011,00:02:18 }
shop[1]={}
You can loop through your JSON string using the following code,
var JSONstring=[{"key1":"value1","key2":"value2"},{"key3":"value3"}];
for(var i=0;i<JSONstring.length;i++){
var obj = JSONstring[i];
for(var key in obj){
var attrName = key;
var attrValue = obj[key];
//based on the result create as you need
}
}
Hope this helps...
It sounds to me like you want to extract the data in the "shop" property of the JSON object so that you can easily reference all of the shop's items. Here is an example:
var json =
{
"data":
{"shop":
[
{"itemName":"car", "price":30000},
{"itemName":"wheel", "price":500}
]
}
},
inventory = [];
// Map the shop's inventory to our inventory array.
for (var i = 0, j = json.data.shop.length; i < j; i += 1) {
inventory[i] = json.data.shop[i];
}
// Example of using our inventory array
console.log( inventory[0].itemName + " has a price of $" + inventory[0].price);
Well, your output example is not possible. You have what is a list of things, but you're using object syntax.
What would instead make sense if you really want those items in a list format instead of key-value pairs would be this:
shop[0]=[7,7,"Michael Jamison",repair,"Blown Head gasket and two rail mounts", 07/22/2011,00:02:18]
For looping through properties in an object you can use something like this:
var properties = Array();
for (var propertyName in theObject) {
// Check if it’s NOT a function
if (!(theObject[propertyName] instanceof Function)) {
properties.push(propertyName);
}
}
Honestly though, I'm not really sure why you'd want to put it in a different format. The json data already is about as good as it gets, you can do shop[0]["carID"] to get the data in that field.

Categories