GR query results pushed to an array; iteration issue
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
09-14-2022 02:24 PM
Community,
Currently having difficulties with pushing results from a grquery into an empty array properly.
var result = [];
var glideRecord = new GlideRecord (table);
glideRecord.addQuery('parameter', 'string');
glideRecord.query();
while(glideRecord.next()) {
gs.info('found' + notesGr.number);
result.push(glideRecord.number)
gs.info('result: ' + result)
}
the while loop is overwriting the previous query result found
this is what the while loop is doing to the array:
x_snc_createnotes: foundNOTE0001072
x_snc_createnotes: result: NOTE0001072
x_snc_createnotes: foundNOTE0001087
x_snc_createnotes: result: NOTE0001087,NOTE0001087
x_snc_createnotes: foundNOTE0001069
x_snc_createnotes: result: NOTE0001069,NOTE0001069,NOTE0001069
x_snc_createnotes: foundNOTE0001086
x_snc_createnotes: result: NOTE0001086,NOTE0001086,NOTE0001086,NOTE0001086
x_snc_createnotes: foundNOTE0001055
x_snc_createnotes: result: NOTE0001055,NOTE0001055,NOTE0001055,NOTE0001055,NOTE0001055
x_snc_createnotes: foundNOTE0001058
x_snc_createnotes: result: NOTE0001058,NOTE0001058,NOTE0001058,NOTE0001058,NOTE0001058,NOTE0001058
- Labels:
-
Scripting and Coding

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
09-14-2022 03:34 PM - edited 04-21-2023 09:30 AM
Did you know that gr[fieldName] is always an empty object and that it only points to the value? I believe this unexpected detail is at the crux of what I see as your 3 issues.
- You're capturing an empty object; a "pointer".
- That object is only a pointer whose target is the gr's current location, which changes on every gr.next(). (!)
- On every gr.next(), all of your captured pointers now point at the new row, meaning all your array entries are simply duplicated pointers since they all point to the same row. (!)
In case you're curious, here is some source conceptual code that can be used to poke and prod and see how this operates under the hood, to gain a better comprehension of what is happening and how to compensate for it in the future.
//NOTE: All of this code is conceptual. It is not verbatim to OOTB in code but it is identical in imitating this small aspect of its function, according to my testing. (JWaters)
var gr = { //this represents the server-defined "GlideRecord" variable
database: [ //this is a simplified demo of the database your GlideRecord is using, which we never see this in our scripts
{number: 'youll see this 1x'}, //row 1/3
{number: 'youll see this 2x'}, //row 2/3
{number: 'youll see this 3x'}, //row 3/3
],
location: -1, //this is the database index that the gr is currently pointing to; -1 is the initial quasi-location
next: function() { //this is a simplified demo of what gr.next() does
this.location++; //Increment the location and,
if (!this.database[this.location]) { //if we then reach the end of the database,
return false; //return false to stop the client's while loop.
} else { //Otherwise, collect pointers for the current row and return the collection.
var self = this; //this will be needed in Object.defineProperty's distinct scope
for (var column in self.database[this.location]) { //iterate this row's columns
var columnPointer = {}; //you see this? It's an empty object, just like you see from gr[column]! THIS is the empty "pointer".
Object.defineProperty(columnPointer, 'toString', { //you don't see this property because it's not enumerable
value: function() { //this function is what toString uses to fetch the actual data
return self.database[self.location][column]; //notice that it's pulling the CURRENT location from the database... this is
} //your issue, as you're storing 2-3+ pointers that, when toStringed, all get the
}); //value tied to the CURRENT location. Store the value, not the pointer.
gr[column] = columnPointer; //see? the empty pointer, not the value, is returned. Go through pointer.toString() to get the value.
}
return true; //continues the while loop
}
},
};
(function yourScript() {
var duplicatedPointers = [];
var intendedResult = [];
while (gr.next()) { //each time this runs, and increments your gr's target row, it also updates the target of all your captured pointers to said row(!)
console.log('processing: ' + gr.number); //this concatenation automatically calls pointer.toString(), showing the actual value
duplicatedPointers.push(gr.number); //here you're just duplicating a pointer that ALWAYS points to the current row.(!!!)
console.log('duplicatedPointers: ' + duplicatedPointers); //concatenating an array to a string will call toString() on each entry (duplicated pointers)
intendedResult.push(gr.number.toString()); //here you're capturing the current value. this is what you want!
console.log('intendedResult: ' + intendedResult); //this does the same as above except this time your entries have your intended values rather than pointers
}
})();
Which prints:
processing: youll see this 1x
duplicatedPointers: youll see this 1x
intendedResult: youll see this 1x
processing: youll see this 2x
duplicatedPointers: youll see this 2x,youll see this 2x
intendedResult: youll see this 1x,youll see this 2x
processing: youll see this 3x
duplicatedPointers: youll see this 3x,youll see this 3x,youll see this 3x
intendedResult: youll see this 1x,youll see this 2x,youll see this 3x
Back to the point, to avoid inadvertently building an array of duplicated pointers you need to convert each pointer to a string and push that string, rather than the the pointer itself, to your array. This way you capture the value of the current row rather than capturing/duplicating a pointer. I suggest doing so in either of these three ways:
arr.push(String(gr.number)); //I prefer this, just cause it's shorter in char length
arr.push(gr.number.toString()); //this is the most common method. It is perhaps more human-readable.
arr.push(gr.getValue('number')); //as mentioned by vkachineni. FYI: this performs some sanitization/validation before returning a value. (NOTE: empty strings come out from this as "null" instead of "")
The reason your text concatenation - gs.log('some text concatenated with ' + gr.number) - is giving the current value is because the text concatenation is automatically calling gr.number.toString(), it's just an inherent part of text concatenation. This is potentially confusing you when compared to array.push(gr.number)'s behavior, making you wonder why gr.number shows the correct value there but not when captured in an array, but now you know.
I hope that helps to not only answer your question but to empower you to better understand and compensate for the various facets of GR in the future! It helped me, as I had to learn a few new aspects to make my concept code perfectly imitate OOTB. 🙂
Kind Regards,
Joseph
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
09-18-2022 08:42 PM
Joseph,
It was a silly mistake that brought forth an important GR concept and a good reminder. Thank you so much for taking the time to have written such elaborate response.
Definitely following and imitating your footsteps and example.
- Christian
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
09-15-2022 09:13 AM
Hello Christian,
Please check with below code:
var result = [];
var glideRecord = new GlideRecord (table);
glideRecord.addQuery('parameter', 'string');
glideRecord.query();
while(glideRecord.next()) {
gs.info('found' + glideRecord.getValue("number"));
result.push(glideRecord.getValue("number"))
gs.info('result: ' + result)
}
This should work in your case.
If my answer helped you in any way then please do mark it as helpful. If it answered your question then please mark it correct and helpful. This will help others with similar issue to find the correct answer.
Thanks