meteor minimongo getting inconsistent collection.findOne() results - javascript

I've been trying to debug a chunk of code for some hours now, banging my head against the wall, and finally pinpointed my issues to a place in the code where assigning the results of a collection.findOne() call to a variable is giving me different data than what I see with a console.log() of the same findOne() on the previous line.
prePostState = function(thisStID) {
console.log(Students.findOne({_id:thisStID}));
var stTemp = Students.findOne({_id:thisStID});
console.log(stTmp);
var testsTemp = stTmp.tests;
The collection object has a 'tests' array. In this instance, the array contains 3 objects as its elements.
While both the console.log() lines return something like this
Object {_id: "eXf9dqQbaemKS24Ti", name: "Student,Name", group: "none", site: "SiteName", tests: Array[3]}
Expanding each shows different data. The first one shows the correct tests: Array[3], the second one shows tests: Array[1], and the single element in that array also has data that is different from the matching element in the full array.
----Update----
Doing some further testing, I've changed the code a bit.
prePostState = function(thisStID) {
console.log(Students.find({_id:thisStID}).fetch()); //1
var stTmp = Students.find({_id:thisStID}).fetch();
console.log(stTmp); //2
console.log(stTmp[0].tests.length); //3
for(var i = 0; i < stTmp[0].tests.length; i++) {
console.log(stTmp[0].tests[i]); //4
}
1 Returns:
[Object]
0: Object
_id: "AqLHB8hT8GxzQ7zyD"
group: "none"
name: "Student,Name"
site: "SiteName"
tests: Array[3]
2 Returns:
[Object]
0: Object
_id: "AqLHB8hT8GxzQ7zyD"
group: "none"
name: "Student,Name"
site: "SiteName"
tests: Array[1]
3 Returns:
3
The for loop at 4 repeats three times and prints out each of the three objects in the tests array.
Obviously this means I can access the data I need. Instead of
var testArray = stTmp.tests;
Which leaves me with an array with only a single element, I will just have to get the length of stTmp.tests, and then use a for loop to access each element by index and insert them into the testArray variable.
So I can continue on, but I still don't understand the behavior I'm seeing. I'm on a bit of a timeline to keep making progress at this point, but when I have some time I may revisit this and try and replicate it in a meteorpad or other form that I can share the full code with.

1) If you modify a return value from Minimongo, don't expect it to persist. Minimongo was specifically written this way, so you are forced to use update operators to update the values.
2) The correct projection API is Coll.find({..selector..}, {fields:{..projection..}})

Related

How to render Array.length from inside of object to html page?

I am using jQuery and got an response from API by using $.ajax. I want to grab the Arrays length from inside each object and display that in the html page. This is what I have done so far.
Here is the API response, i did breakdown of the last object, which contains an array and player names:
{_type: "InjuredPlayers", flaggedTokens: Array(1)} //1 injured player name
{_type: "InjuredPlayers", flaggedTokens: Array(3)} //3 injured players names
{_type: "InjuredPlayers", flaggedTokens: Array(5)} //5 injured players names
{_type: "InjuredPlayers", flaggedTokens: Array(2)} //2 injured players names
>flaggedTokens:Array(2)
>0:{offset: 0, token: "John", type:"UnknownToken"}
>1:{offset: 1, token: "Adam", type:"UnknownToken"}
length: 2
>_proto_:Array(0)
_type: "InjuredPlayers"
>_proto_: Object
In order to grab the length of the Array I can do any of these 2 methods according to this Get length of array inside object
console.log(response.flaggedTokens.length)
1
3
5
2
OR
console.log(response["flaggedTokens"].length)
1
3
5
2
My Failed Attempts: I assigned this output to a variable and tried to loop through and output by doing this:
$.ajax(gameResponse).done(function(response) {
let injuredPlayers = response.flaggedTokens.length;
let injuredPlayersArray = [];
for (let i = 0; i < injuredPlayers.length; i++) {
injuredPlayersArray.push(injuredPlayers[i])
}
$('.injured_players').html(injuredPlayersArray[i])
})
<div class="container">
Team One Total number: <span class="injured_players"></span> //should be 1
Team Two Total number: <span class="injured_players"></span> //should be 3
Team Three Total number:<span class="injured_players"></span> //should be 5
Team Four Toal number: <span class="injured_players"></span> //should be 2
</div>
Clearly I made some mistake which I can't seem to figure this out by myself. I was hoping if someone can guide me through the right direction.
To start with, in your for loop, you are returning the push action, but that's unnecessary and it kills the loop on the first iteration. Also, you have already set the length of the array to a new variable, but then in your for loop, you try to get the length of the new variable. Lastly, you declare injuredPlayersArray in your ajax statement, but based on your post, you recieved 4 separate api responses, so it should be declared outside of your ajax call so that the array doesn't get overwritten with every new call. And you don't need a for loop as you're only working with one array. Here is what it should look like.
let injuredPlayersArray = [];
$.ajax(gameResponse).done(function(response) {
let injuredPlayers = response.flaggedTokens.length;
injuredPlayersArray.push(injuredPlayers)
})
Your other mistake is that you are trying to dynamically display the value in the proper html tag, but you're setting the value for every span tag at the same time. So after your loop is finished, they would all say 2.
To fix that you can add a for loop after all of your api calls are completed (aka NOT inside a $.ajax().done()):
for (let i = 0; i < injuredPlayersArray.length; i++) {
$('.injured_players').eq(i).html(injuredPlayersArray[i])
}
Note: .eq() returns a set of DOM elements that match the selector it is called upon. So $('.injured_players') matches 4 elements on your page and in your for loop, it finds the i-th element in that set (so index 0 is equal to the first span tag) and sets the html for that element.
Note 2: There is an assumption I had to make with your api calls. From the way your api call is storing the length of the flaggedToken array in your response, it seems each ajax response returns a single object with the array of injured players and that you will have 4 separate api calls. However, if that's not the case and the response returns a array of objects, you will need to iterate over the array and get the length for every array in every object one at a time. You can also then ignore my suggestion to move the declaration of injuredPlayersArray to outside the api call. And the second for loop i wrote would go inside the api call.

Aggregate values in a javascript grouped object based on conditions

I am using IE 11.
I have an object array that is grouped using the lodash library. I want to be able to query the object and based on certain conditions come up with sums/counts. So for example, I have this object array.
I would like to have the result seen below but in an object like the image above
As you can see, each company in the group should have certain values based on the following criteria
How many times does 'company x' have a Total Count >3?
How many times does 'company x' have expectingFunding eq ‘Yes’>
How many times does 'company x' have fundedOnIKNS eq ‘No’?
I've tried quite a bit in the last couple of days but not success. I first declared 2 arrays so I can capture the unique values of company name and program. I also created an object to update when conditions were met. The only successful thing I was able to get was to keep it in an grouped object. All the values in the new object were wrong.
Here's an excerpt of the code:
const companiesSummary = {};
for (const company of Object.keys(myData)) {
companiesSummary[company] = {
totalCount: 0,
expectedFunding: 0,
IKNSFunding: 0,
};
for (const { TotalCount, expectedFunding, fundedOnIKNS } of myData[company]) {
companiesSummary[company].totalCount += TotalCount;
companiesSummary[company].expectedFunding += expectedFunding === "Yes";
companiesSummary[company].fundedOnIKNS += fundedOnIKNS === "Yes";
}
}
I get the error,
TypeError: myData[company] is not iterable
Here's a link to the pen
I would still like the result to be in an object array, so I can create an html table later. Any help would be much appreciated. Thank you!
Your code isn't working because you're taking myData, an array, accessing myData[company], an object (company is 0, 1, ...), and you can't iterate through an object with for...of. myData is definitely not the same object in your screenshot.
Your code excerpt might work if your myData object were the object in your screenshot.

why console.log() creating /**id:4**/ and /**ref:4**/ values?

Few mins ago I did this answer and the answer snippet is below
let obj = {staff_changes: []};
let newStaff=[];
for (let i = 0; i < 4; i++) {
newStaff.push({id: 'staff' +i});
obj.staff_changes.push({
id: i,
newStaff: newStaff
});
}
console.log(obj);
If you run this above snippet, you can see /**id:4**/ and /**ref:4**/ . What is this?
When the code on execution time, that was pushing same duplicate values into a array. So I hope at the starting time it's generating a Id:4 and if the same duplicate value will exist, then just it write a comment like /**ref:4**/ where 4 means Id=:4 which is generated already.
So I want to know Is my understand is correct?. If my understanding is correct , then how can we avoid this? Shall I use object.assign() before push the value into array to avoid this?
Your data structure contains multiple references to the same object. console.log is intelligent enough to abbreviate the output.
Note that (AFAIK), the specification does not guarantee any particular output from console.log for objects that aren't instances of String, so you cannot rely on that output being the same across browsers, versions, phases of the moon, etc.
Consider an infinitely recursive data structure like const a = []; a.push(a); console.log(a), which one would you prefer: your computer to lock up while printing an infinitely recursive array or console.log abbreviating it?
const a = []
a.push(a)
console.log(a)
// [
// /**id:1**/
// /**ref:1**/
// ]
Depending on your console tools, they will display an object like this in different ways. Those comments are telling you there is more information deeper in the object.
If you want to see the internals in a consistent way, you can stringify the whole object
console.log(JSON.stringify(obj));
in which case you get:
{"staff_changes":[{"id":0,"newStaff":[{"id":"staff0"},{"id":"staff1"},{"id":"staff2"},{"id":"staff3"}]},{"id":1,"newStaff":[{"id":"staff0"},{"id":"staff1"},{"id":"staff2"},{"id":"staff3"}]},{"id":2,"newStaff":[{"id":"staff0"},{"id":"staff1"},{"id":"staff2"},{"id":"staff3"}]},{"id":3,"newStaff":[{"id":"staff0"},{"id":"staff1"},{"id":"staff2"},{"id":"staff3"}]}]}
In some developer tools, you can expand the object when you log it to the console, but the above string output shows you the whole lot consistently across tools.

SuiteScript / JavaScript Array Indexing Issues

I am working on dynamically generating XML for printing labels. I have an array of values generated with map, the format of this array should end up as such:
[[val1a, val1b, val1c],[val2a,val2b,val2c],[val3a,val3b,val3c]]
I am unable to log to the browser console in this application, so must use provided logging APIs to view the actual values of the array at any given point. The format presented by logging is as such:
val1a,val1b,val1c,val2a...
The values are generated like so:
for(var i = 0; i < lines; i++) {
for(var j = 0; j < quantity; j++){
smCnts.push([i]);
}
}
Where i is the line number of the specific "record", and j is iterating over the quantity, pushing the line number to the array smCnts. Resulting in a dataset like this (assuming line 1 has a quantity of 3, and line 2 has a quantity of 2 etc.):
[[1], [1], [1], [2], [2], [3]]
This array is then mapped using a function that gets values from the lines:
var smLbls = smCnts.map(getData);
Resulting in something like the first array listed in this question.
The problem results when trying to index the array for a specific value:
var foo = smLbls[1];
This returns nothing, I don't even know if it returns null as the logging api returns only: .
However, logging smLbls returns the first mentioned array as described in the second code snippet. What would be causing this issue? I need to be able to get the index of the index of an array like so:
var bar = smLbls[1][3];
Everything else is working as expected, I am just unable to access this data for whatever reason, maybe I am not understanding JavaScript fully?
I am unable to log to the browser console in this application, so must use provided logging APIs to view the actual values of the array at any given point. The format presented by logging is as such:
My advice, use the logs to extract a snapshot of your data:
nlapiLogExecution('debug', 'sample', JSON.stringify(data));
...and work in the browser.

How to properly use dataLayer.push(), to update values, of nested objects, in an array?

Here is my dataLayer array:
dataLayer = [{
'giftBatch' : {
'giftID': '',
'giftAmount': 0,
'giftCount': 0,
'giftUpdate': {
'giftPhase': 'Gift Empty'
}
},
'txBatch': {
'txID': '',
'txTotal': 0,
'txURL': window.location.href,
'txUpdate': {
'txPhase': 'Transaction Opened',
'txT0': new Date(),
'txT1': ''
'txT2': ''
}
}
}];
The console results are: Array [Object1]
Object1 contains the 'giftBatch' and 'txBatch' Objects, as desired.
I have a trigger that fires later to update the object in the dataLayer.
For example, update the 'giftAmount' to 50 and 'giftCount' to 1.
I have tried the following (I am only showing my unsuccessful attempts at modifying 'one object at a time'),
Attempt 1:
dataLayer.push({giftAmount : 50});
Result:
Array [object1, object2]
Object1 is the same as above,
Object2 is a new object with the property of 'Gift Amount' : 50,
Attempt 2:
dataLayer.push({giftBatch.giftAmount: 222});
Result: SyntaxError: missing : after property id
Attempt 3:
dataLayer.push({'giftBatch.giftAmount' : 50});
Result:
Array [object1, object2]
Object1 is the same as above,
Object2 is a new object with the property 'giftBatch.giftAmount': 50
What am I doing wrong here?
According to the dataLayer section here: https://support.google.com/tagmanager/answer/6106899?hl=en
I should be able to edit nested objects values.
PS. This is what I'm using now, and it does work. But, why doesn't push work?
dataLayer[index].giftBatch.giftAmount = 50;
Where index is the index of Object2.
Any help would be great.
Thank you.
It is bad practice to edit existing contents of the dataLayer, but you should just need to send the overriding property value(s) like this:
dataLayer.push({'giftBatch':{'giftAmount' : 50}});
The tag manager starts at the latest Object and will keep looking backwards through previous Objects to determine the current setting of each DataLayer variable, so only giftBatch.giftAmount is overriden with this new push.
Here is an example of preview debugger showing the dataLayer's merged view of a new test Object with properties from previous messages:
Interpreting this Debugger Data Layer view
In this instance, previous messages (#4 and/or #5) pushed at a minimum:
{test:{test:8}} // #6 does not contain test.test so it is from earlier
or at a maximum they could have pushed:
{test:{test:..,foo:..,test3:..}} // #4 if it's been completely shadowed
{test:{test:8,foo:..,test3:..}} // #5 if it has test.test, must have 8
No tags can fire between #3 and #7 as Messages are objects that lack event properties, so any shadowed values from #4&#5 should be considered inaccessible when tracking could next occur on tags that fire on event #7.

Categories