2

For some reason I am having the hardest time get to values of an object stored within an array. Here is how I am populating my array:

var arrActivities = []; 

//other not needed variables here.. 

function logIt(){
firebase.firestore().collection('PostedFunActivities').where("geolocation", ">=", range.lower).where("geolocation", "<=", range.upper).get().then((querySnapshot) =>{
    querySnapshot.forEach((doc) =>{ 
            arrActivities.push(doc.data());                                         
    })
});
       console.log(arrActivities);
       console.log(arrActivities.length);
}

The result of my console.log is the following:

[]
    0: {location: "Mānana Ridge Trail, Pearl City, HI, USA", geolocation: "87z9yj0x5"}
    1: {timePosted: "13:50:05 GMT-1000 (HST)", geolocation: "87zc52x78"}
    2: {userId: "QevGxIV57lZuC92oTjp80N9WcIy2", title: "Koko crater arch"}
    3: {timePosted: "13:46:55 GMT-1000 (HST)", image: "0.1565895502212029"}
    4: {title: "Bike", datePosted: "Fri Jun 12 2020"}
length: 5
__proto__: Array(0)

I feel like i tried a million way to get either the length of the array or the values within, but I cannot get to any of that. Some of my attempts involve suggestions coming from these SO posts (these attempts are to get the lenght):
data.length
Object.keys(data).length

I would really appreciate any suggestions on how to get the length and values of my objects.

*My Objective
I need to get the length of the array which in this case would be 5. Also I need to be able to get into my values for example the the userId within the 3rd element in the array.

user120242
  • 14,918
  • 3
  • 38
  • 52
Fabrizio Botalla
  • 697
  • 1
  • 8
  • 25
  • 1
    `arr.reduce((sum,x)=>Object.keys(x).length+sum,0)`? What problem are you trying to solve? – user120242 Jun 21 '20 at 23:23
  • @user120242 I added my objective to the post, I tried your solution, but I when I log it I still get a 0. – Fabrizio Botalla Jun 21 '20 at 23:32
  • Are you using firebase? `querySnapshot.size` – user120242 Jun 21 '20 at 23:53
  • I am using Firebase, let me add that. – Fabrizio Botalla Jun 21 '20 at 23:54
  • 2
    Did you make sure to await or use a callback to make sure the query results are ready before you try to propagate it? It looks to me like your array was initially empty, and the data was propagated after you console.log'd it, so your code is actually receiving the empty array before the query results were added to it – user120242 Jun 21 '20 at 23:55
  • @user120242 mmm.. I do see what you are saying.. where would you add the await? in that statement I do not have anything that returns.. – Fabrizio Botalla Jun 21 '20 at 23:59
  • It's already in a Promise callback, so it should be ready by then. Did you check the snapshot's `.size`? Or check `.empty`? If it's empty, maybe you filled the array with data later somewhere else? Note, if you are trying to access arrActivities anywhere else, if it runs before the Promise resolves and fills it with data, you will get an empty arrActivites. Also, are you sure arrActivities is within the scope you are trying to access it from? – user120242 Jun 22 '20 at 00:06
  • True.. `.size` returns 5 and `.empty` is false. I am pretty sure everything is within the scope. Also, the only place where I am manipulating arrActivities is in that firebase promise statement. – Fabrizio Botalla Jun 22 '20 at 00:11
  • If you call `logIt` multiple times, there may be times when it's empty; but console.log may still show data when you look at it, because it is showing it by reference (and by the time you go to look it has been filled in). If you have code that tries to access (read) arrActivities outside of that promise, it may be empty on access. If it's snot this, there's probably more information needed. – user120242 Jun 22 '20 at 00:37
  • 1
    Does this answer your question? [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Lennholm Jun 22 '20 at 00:43
  • @Lennholm Not entirely as I am getting the content that I need from my requests. I can see it in my `console.log()`, but I cannot access it to save my life.. – Fabrizio Botalla Jun 22 '20 at 04:33
  • @user120242 Quite interesting because I call logIt on button click so it would get callled only as much as I click on the button.. – Fabrizio Botalla Jun 22 '20 at 04:34
  • 1
    @IlllIl your console.log is outside your Promise then callback. arrActivities has not been populated when you called console.log – user120242 Jun 22 '20 at 05:02
  • @user120242 You were right, thanks for all the help man – Fabrizio Botalla Jun 22 '20 at 05:28

2 Answers2

2

It seems your code is asynchronous:

function logIt(){
    firebase.firestore().collection('PostedFunActivities').where("geolocation", ">=", range.lower).where("geolocation", "<=", range.upper).get().then((querySnapshot) =>{
        querySnapshot.forEach((doc) =>{ 
                arrActivities.push(doc.data());                                         
        })
   });
   
   console.log(arrActivities);
   console.log(arrActivities.length);
}

The .then means that your anonymous arrow function callback will only populate the arrActivities array when the .get() promise resolves.

The reason the console.log was showing a filled array with length but the arrActivites.length wasn't is because of this. Namely, console.log shows the array as it is ("live"), whereas .length accesses the length property of the array when the statement is executed.

Essentially console.loging a variable may asynchronously show that variable as a live reference, so by the time you see the logged output it may be changed from when it was first logged. On the other hand, accessing the length property of the array is guaranteed to be synchronous, meaning that when you log the length of the array, the value logged is unchanging.

One solution for this would be to wrap your logIt function body in a Promise, and then simply wait for the returned arrActivities:

function logIt(){
    return new Promise((resolve, reject) => {
        firebase.firestore().collection('PostedFunActivities').where("geolocation", ">=", range.lower).where("geolocation", "<=", range.upper).get().then((querySnapshot) => {
            querySnapshot.forEach((doc) =>{ 
                arrActivities.push(doc.data());                                         
            })
            resolve(arrActivities);
        });
    });
}


logIt().then((result) => {
    console.log(result.length);
});

zr0gravity7
  • 2,917
  • 1
  • 12
  • 33
0

To get the length of each item in the array:

for (const item of arrActivities) {
    console.log(Object.keys(item).length);
}

To store the lengths of the items in the array in another array:

let arrLength = [];
for (const item of arrActivities) {
    arrLength.push(Object.keys(item).length);
}

To get the length of the array:

console.log(arrActivities.length);

To get the number of items in all objects of the array, i.e. the total number of object values of the items in the array:

let total = 0;
for (const item of arrActivities) {
    total += Object.keys(item).length;
}
console.log(total);
zr0gravity7
  • 2,917
  • 1
  • 12
  • 33
  • 1
    I am not necessarily trying to get the length of each object in the array.I am simply trying to get the length of the array. – Fabrizio Botalla Jun 21 '20 at 23:35
  • This should be trivial, not sure if I am missing something. In any case, please see edit. – zr0gravity7 Jun 21 '20 at 23:44
  • 1
    It really should be very trivial, but for some odd reason I cannot figure it out.. When I `console.log(arrActivities.length);` I get an `undefined`. I starting to think that the way the array is built with the `arrActivities.push(doc.data())` is messing things up. – Fabrizio Botalla Jun 21 '20 at 23:46
  • Can you post more context? Specifically where you are trying to access the array length, and where the array is declared. – zr0gravity7 Jun 21 '20 at 23:48
  • I added some more context. it's a pretty trivial operation, but somehow I am missing something.. – Fabrizio Botalla Jun 21 '20 at 23:51
  • arrActivities.length being undefined means that it is not an array or array-like. – user120242 Jun 22 '20 at 00:33
  • @user120242 What would it be then? From what the log tells me it appears to me to be a very common array of objects. – Fabrizio Botalla Jun 22 '20 at 04:36
  • use `console.log(JSON.stringify(arrActivities))`. Or add a breakpoint in the debugger and check what the local variable values are. – user120242 Jun 22 '20 at 04:46
  • Is there any asynchronous code acting in the `arrActivities` variable? – zr0gravity7 Jun 22 '20 at 04:49
  • 1
    @zr0gravity7 check the main comments on OP for more info: According to OP that segment of code only executes on a button click he controls, and the only place arrActivities is manipulated on is inside the Promise callback – user120242 Jun 22 '20 at 04:54