Reputation: 3407
I am working with the Firebase Realtime Database and would like to collect all the "notes" I have access to - ie. where I am listed as "author" or invited "member".
My database structure illustrated below.
I am currently using the below code to fetch all "notes" I have access to.
return new Promise( (resolve, reject) => {
try{
let notes = []
//Get notes where I am author : uid = my user uid
database.ref('notes')
.orderByChild("access/author")
.equalTo(`${uid}`)
.on('value', (snapshot) => {
snapshot.forEach( (childSnapshot) => {
const note = {
id: childSnapshot.key,
...childSnapshot.val()
}
notes.push(note)
})
})
//Get notes where I am member
database.ref('notes')
.orderByChild(`access/members/${uid}`)
.equalTo(true)
.on('value', (snapshot) => {
snapshot.forEach( (data) => {
const note2 = {
id: data.key,
...data.val()
}
notes.push(note2)
})
})
//Return all notes
resolve(notes)
} catch(e) {}
})
The code does not work. The resulting array does not include notes where I am listed as "member". I suspect the reason being that the database calls are synchronous - they do not wait to be completed before returning the array of all notes.
How can I make sure all notes are fetched before resolving the array?
Kind regards /K
Upvotes: 1
Views: 515
Reputation: 591
You are actually dealing with two promises here, which is one reason that your code won't work. Promises are just context wrappers around asynchronous actions. You have two unrelated synchronous actions (your two database calls), so you'll want those to be wrapped separately.
Start by splitting your code into separate promises, and move your resolve statement into the "on" method of your db call, so that it doesn't get processed before the database call is finished:
const promise1 = new Promise( (resolve, reject) => {
let notes = []
//Get notes where I am author : uid = my user uid
database.ref('notes')
.orderByChild("access/author")
.equalTo(`${uid}`)
.on('value', (snapshot) => {
snapshot.forEach( (childSnapshot) => {
const note = {
id: childSnapshot.key,
...childSnapshot.val()
}
notes.push(note)
})
})
resolve(notes);
});
const promise2 = new Promise( (resolve, reject) => {
try{
let notes = [];
//Get notes where I am member
database.ref('notes')
.orderByChild(`access/members/${uid}`)
.equalTo(true)
.on('value', (snapshot) => {
snapshot.forEach( (data) => {
const note2 = {
id: data.key,
...data.val()
}
notes.push(note2)
})
resolve(notes);
});
})
Then, what you really want here is to resolve the value you get back from the call. Meaning that when this promise is resolve, it collects that value.
Now put your promises in an array, and use Promise.all to wait for both of those to happen.
Promise.all([
promise1,
promise2,
]).then(twoNotesArrays => { //[ [notesFromPromise1], [notesFromPromise2] ]
console.log(notes[0].concat(notes[1])); //[all notes]
});
Upvotes: 2