Javascript Variable Reference Bug? - javascript

I am encountering a weird problem with what I believe to be the way Javascript references variables. The project I am working in is Typescript, but this functionality is from vanilla Javascript.
I have an object all_obj set further up in the code.
The following code:
all = [];
data = [];
console.log(all_obj);
Outputs:
{
"1593561600000": {
"date": 1593561600000,
"volume": 24463,
"value": 165049285,
"rank": 0
},
"1596240000000": {
"date": 1596240000000,
"volume": 24366,
"value": 158841976,
"rank": 0
},
"1604188800000": {
"date": 1604188800000,
"volume": 30034,
"value": 196655815,
"rank": 0
},
This goes on 9 more times with similar objects
}
This, works as expected.
However the following code somehow logs something completely different:
let all = [];
let data = [];
console.log(all_obj);
for (let key of Object.keys(all_obj)) {
all.push(all_obj[key]);
}
this.data.push(
{
brand: 'all_aggregated',
datapoints: [...all],
},
{
brand: 'all_mean',
datapoints: [...all].map((dp: brand_datapoint) => {
dp.value = +(dp.value / dp.volume).toFixed(2);
return dp;
}),
}
);
It logs this:
{
"1593561600000": {
"date": 1593561600000,
"volume": 24463,
"value": 6746.89,
"rank": 0
},
"1596240000000": {
"date": 1596240000000,
"volume": 24366,
"value": 6519,
"rank": 0
},
"1604188800000": {
"date": 1604188800000,
"volume": 30034,
"value": 6547.77,
"rank": 0
},
9 more like this
}
As you can see, in the second example. The "value"'s within the all_obj's children is now in the thousands, instead of the hundreds of millions. Also, it is formatted to 2 decimal places. This is suspiciously the formatting I am doing in this line towards the end of the second code example:
dp.value = +(dp.value / dp.volume).toFixed(2);
How on earth is changing the values propagating back up the code???
Especially through [...all]
This is running in an Angular Project. I have trimmed off the bloat, if you need more info of course ask for it, but I didn't want to paste 300 lines of code in here :)
I have been fighting with this for about 6 hours now, and have completely rewritten the same code in about 15 different ways. So I am completely baffled what is causing this.
Solution!
The issue isn't that the data is propagating back up to all_obj, it's that values were being set in the pink arrow, and were being picked up in the red arrow because they were just referencing to it. I thought [...all] would fix it but that just builds a new array with the same references.

The problem is that you are editing the value on the same object that you started with.
When you do all.push(all_obj[key]);, you are filling all with a bunch of references to the inner objects in all_obj. Since these are simply references, interacting with them changes the same objects as the the ones in all_obj. So when you set the value dp.value =, it is "propagating back up the code" because it is the same object that is inside all_obj.
Since you want to make these changes on a new object for just formatting reasons, you should make a copy of the object and only edit the values there. Since the datapoints seem to be simple, with only simple numbers as properties, you can easily make a copy with
dp = {...dp};
You should do this before you change the value.
You may be thinking that this shouldn't be needed, because of the [...all]. However, that will only make a copy of the all list itself, not of all the content. So basically it is a "new list" that contains all the same references to all the same objects.
You may be interested in Is JavaScript a pass-by-reference or pass-by-value language?
EDIT:
Taking another look, it would probably be better/cleaner to make the copy right as you are building the all array. So instead of doing
all.push(all_obj[key]);
You can do
all.push({...all_obj[key]});
Then you don't need to worry about changing the original data as you manipulate the points for formatting or display.

Related

Pentaho JavaScript JSON - Concatenate json objects into existing JSON document based on keys

Basically what i'm trying to do is to build up a Json document, with it's pieces all spread into smaller Json pieces, all rows containing the Keys needed to insert the smaller Json bits inside the correct json structure.
My problem starts in that i know next to nothing about JavaScript. So i would have to learn JavaScript from scratch(already doing), So i'll describe as best i can the issue and what i want to achieve.
Issues: In every Pentaho / Json post i see a hardcoded(Like This answer, which is helpful but again, hardcoded number of fields) JavaScript to build a pre-formed Json structure, what i need is a way to to insert / create, dynamically built info into a Json Structure. And it also needs Nested Structures.
So, in the start i would bulk build all the Flat Json structure, which can be easily done with the Json output Step, since it outputs built Json objects, the objects themselves can be built dynamically, and then just concatenated(Again i don't know if this is possible).
After the flat part is done, comes the part of concatenating the other objects inside the correct structure, some are just more plain objects, others are Arrays of Objects(Nested part).
This is where i need confirmation from someone who understands this part that it is possible to achieve inside Pentaho JavaScript, or the only way using Pentaho is to build hardcoded structures. Below i'll show in Json examples what i want.
This would be an example of the Flat JSON:
{
"Apolices": [{
"Apolice": {
"APO_numero_apolice": "1321635113",
"APO_ramo": "312",
"APO_data_proposta": "22-05-2018",
"APO_valor_desconto": 0.0,
"APO_valor_liquido": 1550.39,
"APO_cod_parceiro_negocio": "1000",
"APO_inicio_vigencia": "22-05-2018",
"APO_status_apolice": "EMITIDA"
}
},
{
"Apolice": {
"APO_proposta": "3212121",
"APO_data_registro": "08-08-2018",
"APO_numero_apolice": "7891321498",
"APO_ramo": "515",
"APO_data_proposta": "22-03-2018",
"APO_valor_desconto": 0.0,
"APO_valor_liquido": 2150.72,
"APO_cod_parceiro_negocio": "7548151100",
"APO_inicio_vigencia": "22-07-2018",
"APO_status_apolice": "EMITIDA",
"APO_produto": null,
"APO_codigo_corretor": "812182",
"APO_fim_vigencia": "22-05-2019",
"APO_valor_bruto": 2320.8,
"APO_percentual_comissao": 19,
"APO_iof": null
}
}
]
}
Then in the course of said implementation, the desired outcome would be something like :
{
"Apolices": [{
"Apolice": {
"APO_numero_apolice": "1321635113",
"APO_ramo": "312",
"APO_data_proposta": "22-05-2018",
"APO_valor_desconto": 0.0,
"APO_valor_liquido": 1550.39,
"APO_cod_parceiro_negocio": "1000",
"APO_inicio_vigencia": "22-05-2018",
"APO_status_apolice": "EMITIDA"
},
"Item": {
"ITE_ano_fabricacao": "2001",
"ITE_modelo": "FOCUS SEDAN GHIA 2.0 MPI 16V 4P",
"ITE_ano_modelo": "2001",
"Cobertura": [{
"COB_cod_cobertura": "21",
"COB_valor_importancia": "50000",
"COB_valor_premio": "415,71",
"COB_cobertura": "RCF-V - Danos Materiais"
},
{
"COB_cod_cobertura": "17",
"COB_valor_importancia": "16712",
"COB_valor_premio": "1165,96",
"COB_cobertura": "Colisão,Incêndio e Roubo\/Furto"
}
]
}
},
{
"Apolice": {
"APO_proposta": "3212121",
"APO_data_registro": "08-08-2018",
"APO_numero_apolice": "7891321498",
"APO_ramo": "515",
"APO_data_proposta": "22-03-2018",
"APO_valor_desconto": 0.0,
"APO_valor_liquido": 2150.72,
"APO_cod_parceiro_negocio": "7548151100",
"APO_inicio_vigencia": "22-07-2018",
"APO_status_apolice": "EMITIDA",
"APO_produto": null,
"APO_codigo_corretor": "812182",
"APO_fim_vigencia": "22-05-2019",
"APO_valor_bruto": 2320.8,
"APO_percentual_comissao": 19,
"APO_iof": null
}
}
]
}
The Json Objects of "Item" and "Cobertura", and others, would come as already built Json objects, with the necessary keys to insert the entire object in the correct position of the structure.
I have done next to no coding myself as of yet since i'm still learning JavaScript, but i already know that Pentaho's JavaScript is somewhat limited in resources, that's why i'm asking ahead if this is even possible inside Pentaho/Kettle
Don't be afraid of the resource limitations for Javascript in PDI. It uses the official Rhino OpenSource project which is 100% ES6 compatible.
Of course, the dynamic nature of JS makes it a little bit slower, but I do not think the difference will be significant unless you have a continuous input flow of millions per minutes.

Remove object key prefixes nodejs

This is my first post. I don't like ask help in forums, but I have no choice. I spent a lot of days trying resolve this but I haven't found any solution.
All my problem start with an database query that returns this.
{
"prod_format": "400 ml",
"prod_brand": "Marca",
"prod_image": "192.168.1.45/mini/1046332bb531ab3.jpg",
"prod_name": "Gel de baño o ducha",
"prod_pvp": 2.20,
"prod_shops": [
{
"prod_price": 2.29,
"prod_shop": {
"prod_shopID": 2,
"prod_shop_name": "Tienda",
"prod_shop_image": "192.168.1.45/shops/d4d4sw2.jpg"
}
},
{
"prod_price": 2.19,
"prod_shop": {
"prod_shopID": 5,
"prod_shop_name": "Tienda",
"prod_shop_image": "192.168.1.45/shops/g4hbe72.jpg"
}
}
]
}
I want remove prefixes of keys, prod_ and shop_ in this case.
I can't do this by hand because this is only one of multiple queries that i use, and this data can change, i need an dynamic function that remove these prefixes, to use with more prefixes and more queries.
So far I have been trying:
Recursive function that calls itself to remap inside objects and
arrays, but it doesn't work because NodeJS is asynchronous and make an
loop that never ends.
Use an list function that gets all keys/values to make a new object
with renamed keys, but i cant found anything that works with complex
objects.
Use chained promises, i can't get that it works, but i think that
it is the best way to do this.
In conclusion I want an function that if I put the upper object, I get this code.
{
"format": "400 ml",
"brand": "Marca",
"image": "http://192.168.1.45/mini/1046332bb531ab3.jpg",
"name": "Gel de baño o ducha",
"pvp": 2.20,
"shops": [
{
"price": 2.29,
"shop": {
"shopID": 2,
"name": "Tienda",
"image": "http://192.168.1.45/shops/d4d4sw2.jpg"
}
},
{
"price": 2.19,
"shop": {
"shopID": 5,
"name": "Tienda",
"image": "http://192.168.1.45/shops/g4hbe72.jpg"
}
}
]
}
PS:
I can't edit the original object, because it comes of elasticsearch and i can't edit object keys.
Thanks in advance, I hope that anyone can help me.
Why don't you simply treat your Json data as a string and then replace '"_prod' with '"'? That would remove all occurances of this prefix.
myJsonString.replace('"_prod', '"');
Update: If your values may contain your prefixes, you better use regular expressions instead, just to make sure you only change the keys.

Need an algorithm to convert string to JSON with javascript

I'm calling an api for the history of an ID which returns a string object that looks like this:
09304790130000--09304790090000
09304790130000--09304790120000
09304790090000--09304790010000
09304790120000--09304790020000
09304790120000--09304790030000
09304790120000--09304790110000
09304790110000--09304790050000
09304790010000--042322003
09304790020000--042322002
09304790030000--042322001
09304790050000--042322004
I could do so much more with it if I could figure out how to use JavaScript to convert it to JSON so it would look like this:
{
"name": "09304790130000",
"children": [{
"name": "09304790090000",
"children": [{
"name": "09304790010000",
"children": [{
"name": "04 2322-003"
}]
}]
}, {
"name": "09304790120000",
"children": [{
"name": "09304790020000",
"children": [{
"name": "04 2322-002"
}]
}, {
"name": "09304790030000",
"children": [{
"name": "04 2322-001"
}]
}, {
"name": "09304790110000",
"children": [{
"name": "09304790050000",
"children": [{
"name": "04 2322-004"
}]
}]
}]
}]
}
Is there an algorithm I can use that can construct the object I need regardless of how complicated the "tree" becomes?
EDIT for clarity:
The "--" in the string represents the relationship of the ID's. The left ID is the parent of the ID right of the dashes. So the ID that I feed the api, "09304790130000" has two children, each could have more children until they reach the current 9-digit ID.
What you have here is an input that is in a custom format. What you need to handle it is a regular expression. (Although your format might be simple enough that a full on regex function is not required so much as splitting on separators?) You need to do is break the input string up and loop over the components and put those into your desired data structure (which sounds like it would be some kind of tree). The high level pseudo-code would be something like:
Take line of input.
Break on "--".
Create root node from the left side if the tree is empty, otherwise just find the existing node.
Add child from right side to the parent.
Getting it into the JSON format you want may require also writing a function that iterates over the tree and writes a string in that format... although if you are using existing libraries and data types this probably already exists.
EDIT: To expand on the last bit, to get the format you want would mean a Pre-order traversal of the tree. At each step you just add the formatting and name to the JSON String. One of these libraries should have the capabilities you need, although obviously you can write a tree data structure and traversal function yourself if you need to.

json - look for value and key

I'm quite new to programming and I been googling but couldn't find exactly what I'm looking for.
ok I send a request by ajax and I get response similar to this (the original json is much more complicated)
{
"shelf": {
"genre": {
"title1": {
"date": "date",
"author": "name",
"featured": "N"
}
"title2": {
"date": "date",
"author": "name",
"featured": "Y"
}}}
now I need to do find a "book" which is featured. So I have been looking for a way to look for featured = Y and get it's title in this case "title2".
The best way I could figure out is that when I create the json (in php) when something is featured I can create a new key => value at the same level as "shelf"
"shelf": {
"genre": {
"title1": {
/.../
}
"title2": {
/.../
}}}
"featured": {
"genre": "featuredTitle"
"genre2":"featuredTitle2"
}}}
and then access it in javascript like this:
response.featured['genre'];
and then get all the data by going to
response.shelf.genre.title
but there must be a better way to do it... this gets very messy when the json is very complicated.
Thanks,
Tom
Almost there. You can loop through a JSON object quite easily, JSON is a very friendly format.
var genres = response.shelf.genre;
for (title in genres) {
if (genres.hasOwnProperty(item)) {
var bookTitle = title;
var featured = genres[title].featured;
}
}
The hasOwnProperty is a safety feature you should always use when looping through a JSON object. You can find out more about it here.
More on JSON
JSON solely consists of Javascript Objects and Arrays, one or the other. So even if the stack is complicated, you can always parse it by traversing either an object or an array, and so long as you know the structure of the JSON, it is easy to parse.
// Objects:
myJSON.subObject.anotherSubobject.andAnotherOne;
// Arrays:
myJSON[0]; // accesses first item in array...
myJSON.subObject[2]; // accesses third item in the subObject array.

parsing JSON object with Jquery problem

Hi I am trying to parse the following bit of json with Jquery so far I can get everything out of the results that I want apart from one crucial piece of information the performance tags.
Each json result is wrapped in an event tag and then within this there is info like time and date etc formatted in the following way
"location": {
"lng": -0.1187418,
"city": "London, UK",
"lat": 51.4681089
},
"start": {
"time": "19:30:00",
"datetime":"2010-02-16T19:30:00+0000",
"date": "2010-02-16"
},
I have managed to loop through this and parse it to html. However there is one set of tags for 'performance' that are formatted differently.
"performance": [{
{
"artist": {
"uri": "http://www.songkick.com/artists/288696-vampire-weekend",
"displayName": "Vampire Weekend",
"id": 288696,
"identifier": [{"mbid": "af37c51c-0790-4a29-b995-456f98a6b8c9"}]
}
"displayName": "Vampire Weekend",
"billingIndex": 1,
"id": 5380281,
"billing": "headline"
}
}],
now in my for loop i am running the following code which displays the performance information in the console.
var events = data.resultsPage.results.event;
for (var i = 0, l = events.length; i < l; i++) {
console.log(events[i].performance); }
However when i try to go into the structure like i have been with the other elements I get returned undefined i.e
console.log(events[i].performance.displayName);
Do I have to do this in a different way because of the use of the [ ] brackets in the performance tag in the Json?
Thanks in advance
Assuming that what you posted is not exactly what your JSON looks like (because what's posted has a syntax error), the "performance" attribute is an array of objects. To get at the "displayName", therefore, you'd need to know which element of the "performance" array you wanted. You'd then access it by index.
console.log(events[i].performance[j].displayName);
(assuming you looped through the "performance" array with the variable "j".)
Try to validate your returned JSON object here, I guess there is some issue with the JSON output..

Categories

Resources