I'm working on a NodeJS/VueJS app and I encounter some strange behavior and I am not sure if it is something I am doing wrong or something else.
I have 2 arrays, one array of objects that contains campaigns and one array of objects that contains all promotions associated to all campaigns.
Each Campaign object contains, at this point, an empty array called promos, where I want to push all the promotions for each campaign.
for (var i = 0; i < campaigns.length; i++) {
for (var j = 0; j < campaignsPromo.length; j++) {
if (campaignsPromo.length > 0) {
if (campaigns[i].IDCampaign == campaignsPromo[j].IDCampaign) {
if ((campaignsPromo[j].associated == 1) && (campaignsPromo[j].validated == 1)) {
campaigns[i].promos.push(campaignsPromo[j]);
console.log("Validated Campaign ID " + campaigns[i].IDCampaign);
console.log("Promo ID " + campaignsPromo[j].IDPromo);
} else if ((campaignsPromo[j].associated == 1) && (campaignsPromo[j].validated == 0)) {
campaigns[i].unvalidatedPromos++;
console.log("Unvalidated Campaign ID " + campaigns[i].IDCampaign);
console.log("Promo ID " + campaignsPromo[j].IDPromo);
}
}
} else {
console.log("No promos!");
}
}
}
At first, the code seems to be doing what is supposed to do and it checks out with my test data set.
However, in the end, all campaigns end up having the same promotions.
Campaigns With No Promos: [{"IDCampaign":7,"campaignName":"dadsadafds","startDate":"2022-02-03","endDate":"2022-02-28","unvalidatedPromos":0,"promos":[]},{"IDCampaign":3,"campaignName":"Tarzan 3","startDate":"2022-02-02","endDate":"2022-02-06","unvalidatedPromos":0,"promos":[]},{"IDCampaign":1,"campaignName":"Tarzan","startDate":"2022-02-01","endDate":"2022-03-01","unvalidatedPromos":0,"promos":[]},{"IDCampaign":2,"campaignName":"Tarzan 2","startDate":"2022-02-01","endDate":"2022-02-08","unvalidatedPromos":0,"promos":[]},{"IDCampaign":4,"campaignName":"Tarzan 4","startDate":"2022-02-01","endDate":"2022-02-05","unvalidatedPromos":0,"promos":[]},{"IDCampaign":5,"campaignName":"Jabe 1","startDate":"2022-02-01","endDate":"2022-02-05","unvalidatedPromos":0,"promos":[]},{"IDCampaign":6,"campaignName":"dadsada","startDate":"2022-02-01","endDate":"2022-02-08","unvalidatedPromos":0,"promos":[]},{"IDCampaign":8,"campaignName":"Black Friday","startDate":"2022-02-01","endDate":"2022-02-28","unvalidatedPromos":0,"promos":[]}]
Validated Campaign ID 1
Promo ID 1119
Unvalidated Campaign ID 1
Promo ID 107
Campaigns With Promos: [{"IDCampaign":7,"campaignName":"dadsadafds","startDate":"2022-02-03","endDate":"2022-02-28","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":3,"campaignName":"Tarzan 3","startDate":"2022-02-02","endDate":"2022-02-06","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":1,"campaignName":"Tarzan","startDate":"2022-02-01","endDate":"2022-03-01","unvalidatedPromos":1,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":2,"campaignName":"Tarzan 2","startDate":"2022-02-01","endDate":"2022-02-08","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":4,"campaignName":"Tarzan 4","startDate":"2022-02-01","endDate":"2022-02-05","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":5,"campaignName":"Jabe 1","startDate":"2022-02-01","endDate":"2022-02-05","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":6,"campaignName":"dadsada","startDate":"2022-02-01","endDate":"2022-02-08","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":8,"campaignName":"Black Friday","startDate":"2022-02-01","endDate":"2022-02-28","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]}]
This is the content of campaignsPromo:
[ { IDCampaign: 1,
IDPromo: 1119,
promoType: 'CHRISTMASS',
associated: 1,
validated: 1,
promoName: 'Test Promo 1',
beginDate: '2020-11-26',
endingDate: '2020-11-29' },
{ IDCampaign: 1,
IDPromo: 107,
promoType: 'CHRISTMASS',
associated: 1,
validated: 0,
promoName: 'Test Promo 2',
beginDate: '2019-12-21',
endingDate: '2019-12-23' } ]
Any ideas? From where I'm standing, I am not doing anything wrong but it wouldn't be the first time I'm missing the obvious.
PS: Please ignore the fact my campaigns are called "Tarzan".
You didn't share the offending code, so I'll give a generic answer.
When the symptom is that a bunch of all objects seem to have a property that is the same array of items, it is likely caused by exactly that. Each object may be sharing the same array instance.
A typical mistake is something like the following:
var items = [];
var containers = [];
for (let i = 0; i < 3; ++i) {
items.push(i);
let container = {};
container.items = items;
containers.push(container);
}
console.log(containers);
Although one might expect, or even have intended to get 3 objects like this:
[
{ items: [ 0 ] },
{ items: [ 0, 1 ] },
{ items: [ 0, 1, 2 ] }
]
The items array is actually the same instance of an array. And what you actually get is more like:
[
{ items: [ 0, 1, 2 ] },
{ items: [ 0, 1, 2 ] },
{ items: [ 0, 1, 2 ] }
]
In fact, the stack snippet visualizer actually does a better job visualizing this because it outputs:
[
{
"items": [
/**id:3**/
0,
1,
2
]
},
{
"items": /**ref:3**/
},
{
"items": /**ref:3**/
}
]
In this way, it tries to inform you that it is actually the same array by giving it a ref:3 label and just marking the values of the other properties with the same ref:3 label as a comment.
Causes I see typically stem from a misunderstanding of what it means to assign an array to a property. Doing so does not create a copy of the array. Both objects refer to the same array.
This can be strange because: it can appear to be correct in a debugger by inspecting the contents of your array as your are stepping through a loop. Even if we had added log messages like console.log(items) or even console.log(container) inside the loop, we'd probably still not have enough of a clue that something went wrong because the contents of that one array instance change with each iteration of the loop and we can dump versions of it as text that appear to be correct, but then unwittingly change the contents of the array on the next iteration.
But if we log the entire containers array after the loop, you'll find that each object has the same instance of the array. Assining an array isn't bad if it's only one object that gets the array assigned to it, but if you assign the same array to properties of multiple objects, or in a loop, you may run into this problem.
One possible habit-breaker you can try is to inspect all objects in a second loop after your primary loop rather than sneaking your logging code directly into the first loop. It's less efficient, but if you're often making these kinds of mistakes, it can help you find problems and achieve correctness.
Another habit breaker is to console.log(JSON.stringify(foo)) rather than console.log(foo) because console.log in the browser actually remembers the reference of the object and shows you its current contents, rather than its contents at the time it was logged. This is different depending on the platform, where node.js will log as text instead of by reference.
Good luck and be careful!
I have JSON String as the one below which is returned from the previous function. It is a string, not object.
{
"qs1": {
"mistake": [{
"id": 1,
"name": "Subject-Verb Agreement Errors."
}, {
"id": 1,
"name": "Sentence Fragments."
}, {
"id": 1,
"name": "Missing Comma After Introductory Element."
}]
}
}
I converted it into an object by using Jquery.parseJSON() now I want to use length to find a number of mistakes.
Problem:
the first key qs1 of the returned JSON can be different like qs2,qs3 & so on. I don't want to use a loop to get the key name qs1,qs2 because it will take a lot of time in only getting a key name and if I have a lot of questions. Also, I don't know the number of questions.
Is there is any way to check qs1.mistake.length>0 without knowing the key name(qs1).
Below is my function:
function SelectiMstake(value) {
alert(value);
var value2 = jQuery.parseJSON(value);
var NewHtml="";
if(value2.mistake.length>0) {
alert("mistake found");
//for(var mistakei = 0; mistakei < value2.mistake.length; mistakei++) {
// NewHtml+= "<input type='check' value='"+ value2.mistake[mistakei] +"'>"+ value2.mistake[mistakei] +"<br>";
// }
//$("#DisplayMistakes").html(NewHtml);
} else {
alert("No mistakes found in the following Question");
}
}
if there is no way I want to stick with my question part when I get JSON string then I want to remove {"qs1": from the start of the string and } from the last. Don't use a character to remove from the start otherwise {"qs12": this will give the wrong result.
Use Object.values(), and just select the first element, or loop through the values (Which is now an array), if you want to check each qs*:
var json = '{"qs1":{"mistake":[{"id":1,"name":"Subject-Verb Agreement Errors."},{"id":1,"name":"Sentence Fragments."},{"id":1,"name":"Missing Comma After Introductory Element."}]}}';
var parsed = JSON.parse(json);
var vals = Object.values(parsed);
console.log(vals[0]);
console.log(vals[0].mistake.length); // 3
Solved the question on my own, see answer
Using jQuery 3.2.1 and Raphael 2.1.1, if this matters
In my Raphael .js I first create some objects without any data and push them into an array, e. g. (.attr omitted):
var objarr = [];
var obj1 = rsr.path("M ... z");
objarr.push(obj1);
After this, I want to take data from a JSON file (an array named "regions" of multiple entries that consist of multiple key-value pairs (validated through JSONLint) and append it as data by id. It looks like this:
{
"regions": [{
"id": "0",
"var1": "foo1",
"var2": "bar1",
},
{
"id": "1",
"var1": "foo2",
"var2": "bar2",
},
// And so on for every object
]
}
I use the following code (localhost is used because otherwise I get a cross-access error:
for (var i = 0; i < objarr.length; i++)
{
var jq = $.getJSON("http://localhost:8000/data.json",{id: +i},function(t){
console.log( "success" );
})
.done(function(objdata){
console.log("success2");
$.each(objdata.regions, function(key, val){
objarr[i].data(key,val);
});
})
.fail(function(t){
console.log("error");
})
.always(function(t){
console.log("complete");
});
}
The console gives me both successes, but after this I get an error "Cannot read property 'data' of undefined". alert(key) and alert(val) give 0 and [object Object] respectively for every call. I tried adding the following to .done:
var items = [];
$.each(objdata.regions, function(key, val){
items.push("id" + key + ":" + val);
console.log(items);
});
The result was a string that went ["id0:[object Object]"],["id0:[object Object]", "id1:[object Object]"] and so on until it had objarr.length ids, repeating the needed amount of times. If I add [i] to objdata.regions, I get no console messages about items[] content at all.
I also found two somewhat closely related questions ("1" and "2"), checked the jQuery documentation for .getJSON(); and Raphael documentation for Element.data();. I've tried the following to check validity of my calls:
console.log(objdata) in the beginning of .done -- returns full base object of JSON data
console.log(objdata.regions) in the beginning of .done -- returns array of objects of JSON data
console.log(objdata.regions[i]) in the beginning of .done -- returns undefined
console.log(objdata.regions[0]) in the beginning of .done -- returns first object (works for every object)
I've used objdata.regions[0] in the snippet with items[] and the adding seems to work properly (console shows the keys and values being added to the array). However, it still doesn't work with objarr[i].data(key,val) (as well as ""+key and "$key").
I have two questions:
1. How do I acquire the key-value pairs properly while looping?
2. How do I append these pairs as data to a Raphael object?
I moved the for loop inside .done() and everything is appended successfully:
.done(function(objdata){
for (var i = 0; i < objarr.length; i++)
{
console.log("success2");
$.each(objdata.regions[i],function(key, val){
objarr[i].data(key, val);
});
}
})
Total JSON noob here. I'm trying to cycle through some JSON to pull out the first image from an array inside the object, and after 4 hours of having at it, I've decided I probably need some help.
I'm able to pull every value I need out of the object where I know the key, but I have some data that has non consistent key names that I need to basically iterate through looking for a partial match and then pulling the first on of these results.
The Json structure of the unknown element is structured like this:
"custom_fields": {
"content_0_subheading": [
"Title text"
],
"content_1_text": [
"Some text"
],
"content_2_image": [
[
"http://staging.livelivelyblog.assemblo.com/wp-content/uploads/2013/09/wellbeing-260x130.jpg",
260,
130,
true
]
],
"content_2_caption": [
""
]
}
What I'm after is the content_2_image in this case, but in another entry it could be content_20_image for all I know (there's a lot of data being pulled).
Any ideas of the best way to cycle through these unknown keys looking for a partial match on '_image' in the key or something, would be VERY appreciated.
Thanks!
You can't just search through every field with a partial match, so you'll have to iterate through every field and then check the field names for the match. Try something like this:
var json = {
"content_0_subheading": [
"Title text"
],
"content_1_text": [
"Some text"
],
"content_2_image": [
[
"http://staging.livelivelyblog.assemblo.com/wp-content/uploads/2013/09/wellbeing-260x130.jpg",
260,
130,
true
]
],
"content_2_caption": [
""
]
}
for (var key in json) {
if (json.hasOwnProperty(key)) {
if (/content_[0-9]+_image/.test(key)) {
console.log('match!', json[key]); // do stuff here!
}
}
}
Basically, what we're doing is:
1) Loop through keys of json object for (var key in json)
2) Ensure the json has the property, and we're not accessing keys we don't want if (json.hasOwnProperty(key))
3) Check if key matches the regular expression /content_[0-9]+_image/
3a) Basically, test if it matches content_ANY NUMBERS_image where ANY NUMBERS is equal to at least one digit or more
4) Use that data however you please console.log(json[key])
Hope this helps!
You could use for ... in
for (key in object) {
// check match & do stuff
}
var json = JSON.parse(YOUR_JSON_STRING).custom_fields, //Fetch your JSON
image; //Pre-declare image
for(key in json){ //Search each key in your object
if(key.indexOf("image") != -1){ //If the index contains "image"
image = json[key]; //Then image is set to your image array
break; //Exit the loop
}
}
/*
image[0] //the URL
image[1] //the width
image[2] //the height
image[3] //your boolean
I have a very large json like :
raw_obj= {"001" : {....}, "002" : {....}};
and I have an another json object which is just returned from server :
search_result = {["001", "005", "123"]};
I want to do something like
$.each(search_result, function(i,val){
alert(raw_obj.search_result[i]);
});
Is it possible? I don't want to loop through those 2 objects because in practical, there will be have around 2000 elements in a "raw_json". Which means the worst case is 2000x2000 times loop per one query.
var raw_obj= {"001" : {'...'}, "002" : {'...'}};
var search_results = ["001", "005", "123"]; // just an array
$.each(search_results, function(i, result) {
alert(raw_obj[result]);
});
The search results are an array (ie, list), not an object (ie, map) and so the syntax should be modified as above. If you have no control over the server response, use string parsing to build a new array.