Reputation:
So I have a function which reads from Firebase database and then creates an array of objects. I have defined variable key
, but it is still unavailable.
var usersList = [];
const ref = firebase.database().ref()
function fetchUsers() {
ref.child('users').once('value').then(snap => {
var promises = [];
snap.forEach(childSnap => {
var key = childSnap.key
promises.push
(ref.child(`users/${key}/points`).once('value')
);
});
return Promise.all(promises);
}).then(function(snapshots) {
return snapshots.map(snapper => {
var points = snapper.val()
return {uid: key, points: points};
})
}).then(function(usersList) {
console.log(usersList)
})
}
And this is the error I get...
(node:11724) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ReferenceError: key is not defined
If i just do: key = childSnap.key
, then every object's uid
is the same.
Upvotes: 1
Views: 1591
Reputation: 1074138
key
is only defined within the forEach
callback. Naturally you cannot then reference it from within the second then
callback. Moreover, which key
would it be? For the first entry? The second? Third?
Instead, you need to return the key with the value:
function fetchUsers() {
ref.child('users').once('value').then(snap => {
var promises = [];
snap.forEach(childSnap => {
var key = childSnap.key;
promises.push(
ref.child(`users/${key}/points`).once('value').then(
snapper => ({key, snapper}) // **
)
);
});
return Promise.all(promises);
}).then(function(snapshots) {
return snapshots.map(({key, snapper}) => { // **
var points = snapper.val();
return {uid: key, points: points};
});
}).then(function(usersList) {
console.log(usersList);
});
}
On the first **
line above, we're transforming the result from once
so it returns an object with both the key and "snapper".
On the second **
line, we're using destructured parameters to receive those objects as the distinct key
and snapper
parameters.
FWIW, if you want to aggressively use concise arrows:
function fetchUsers() {
ref.child('users').once('value').then(snap =>
Promise.all(snap.map(childSnap => {
const key = childSnap.key;
return ref.child(`users/${key}/points`)
.once('value')
.then(snapper => ({key, snapper}));
}))
).then(snapshots =>
snapshots.map(({key, snapper}) => ({uid: key, points: snapper.val()}))
).then(usersList => {
console.log(usersList);
});
}
Also note the use of map
rather than declaring an array and pushing to it from a forEach
callback. :-)
Upvotes: 1