1

I'm stuck on an issue where I'm parsing the results from an API in getSubscriptions(). This calls getUserSubs() which returns the following object:

expected result

When I call on subscriptions I get the expected array console (See "Works") snippet.

But when I try to iterate on the array subscriptions (See "Doesn't work"), then the contents of the function are not even called.

userSubs() is called for API data

async function getUserSubs(userId) {
  const ref = collection(db, "users", userId, "subscriptions")
  let subList = []
  try {
    const subIds = await getDocs(ref)
    subIds.forEach(subRef => {
      const docRef = subRef.data()
      getDocData(docRef.product).then(product => {
        subList.push(product)
      })
    })
    return subList

  } catch (e) {
    console.error("Error in getting subscriptions: ", e)
    return []
  }
}

Works

function getSubscriptions(userId) {
  getUserSubs(userId).then(subscriptions => {
    console.log(subscriptions)  // Works as intended 
  }
}

Doesn't work

function getSubscriptions(userId) {
  getUserSubs(userId).then(subscriptions => {
    subscriptions.forEach(x => {
      console.log(x)  // ISSUE: This isn't called 
    })
}

Also doesn't work

let a = []
getUserSubs(userId).then(subscriptions => {
  subscriptions.forEach(x => a.push(x))
})
console.log(a)

I know there are similar questions asked but after reading them I'm still not able to resolve my issue.

Similar issues:

12
  • 3
    Please edit your question to include data as text, rather than a picture of text. It would probably be easiest if you use console.log(JSON.stringify(variable, null, 2)) and pasted the result here. Then we wouldn't need to see all of the [[Prototype]] nonsense :). Commented Dec 15, 2021 at 3:17
  • The contents of the array returned are objects, not arrays. An object does not have a .forEach() method. Have you checked the console for errors? Commented Dec 15, 2021 at 3:20
  • I've tried to mock AJAX call, you can clearly see, It is working as expected link Commented Dec 15, 2021 at 3:21
  • Do read weird array behaviour in javascript for more information about why using console.log works and what that i means. Commented Dec 15, 2021 at 3:21
  • 1
    See stackoverflow.com/questions/23667086/… for why your third attempt doesn't work. Commented Dec 15, 2021 at 3:24

2 Answers 2

1
getUserSubs(userId).then(subscriptions => {
    console.log(subscriptions)  // Works as intended 
}

No it doesn't. It only appears so because you are inspecting the live array that was mutated after it has been logged to the console.

Also doesn't work:

let a = []
getUserSubs(userId).then(subscriptions => {
  subscriptions.forEach(x => a.push(x))
})
console.log(a)

Yes, for rather obvious reasons: the array is logged before you fill it. It would need to be either

getUserSubs(userId).then(subscriptions => {
  let a = []
  subscriptions.forEach(x => a.push(x))
  console.log(a)
})

or

let a = []
const subscriptions = await getUserSubs(userId)
subscriptions.forEach(x => a.push(x))
console.log(a)

But none of these will solve your core problem: getUserSubs returns an empty array before it gets filled, in the lines

subIds.forEach(subRef => {
  const docRef = subRef.data()
  getDocData(docRef.product).then(product => {
    subList.push(product)
  })
})
return subList

you never wait for the getDocData promise. If you change that to

let subList = []
for (const subRef of subIds) {
  const docRef = subRef.data()
  const product = await getDocData(docRef.product)
  subList.push(product)
}
return subList

or just

return Promise.all(subIds.map(subRef => {
  const docRef = subRef.data()
  return getDocData(docRef.product)
}))

it would work, as described in the question you already found.

(This might still not work. subIds looks suspiciously like a firebase snapshot, which is not an array and can neither be iterated nor does it have a .map method. In that case, you'll need to use forEach+push manually).

Sign up to request clarification or add additional context in comments.

2 Comments

But shouldn't the getUserSubs() be fine since I do get a result (top screenshot) but I just can't seem to iterate through it? Which is your last point because yes I'm using Firebase v9 so I'll have to adapt the answer.
@engineer-x No, you're not getting a result, the array is empty when you get it. Iterating it immediately will iterate 0 entries.
0

Honestly I wouldn't use the forEach() method. I think all you need to do to fix this is iterate over the results in a normal for loop.

for(let subscription of subscriptions) {
   console.log(subscription);
}

OR

for(let index in subscriptions) {
   console.log(subscriptions[index]);
}

If this doesn't do the trick, I'll open up a sandbox and look more in depth.

5 Comments

Mind If you could explain I wouldn't use the forEach() method What's wrong with forEach if subscriptions is an array...
BTW, You shouldn't use for..in loop with arrays.
@decpk I added the expected result in the original question.
@edward I tried both and still had the same result. I also tried the for (let i = 0; i < subscriptions.length; subscriptions++).
Ok please edit your post with the array that's going wrong and I'll put them into a sandbox. As to why I wouldn't use the forEach method, I guess it really comes down to personal preference but I think the for loops using of and in are cleaner but anecdotally, I've run into instances where forEach failed when for loops didn't.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.