Make Code With Firebase Asynchronous

Make code with Firebase asynchronous

When this happens, the solution is usually to move the operation inside the callback:

databaseRef.child("questions").child("questionNumber: " + questionNum).child("title").observeSingleEvent(of: .value, with: { snapshot in
print(snapshot.value ?? "")
question.title = (snapshot.value as? String)!

databaseRef.child("questions").childSnapshot(forPath: "questionNumber: " + questionNum).childSnapshot(forPath: "description").observeSingleEvent(of: .value, with: { snapshot in
print(snapshot.value ?? "")
question.desc = (snapshot.value as? String)!
self.questions.append(question)
})
})

But in this case I wonder why you don't simply load the entire question in one go:

FIRDatabaseReference qref = databaseRef.child("questions").child("questionNumber: " + questionNum)
qref.observeSingleEvent(of: .value, with: { snapshot in
var question = questionMGR()
question.title = (snapshot.childSnapshot(forPath: "title").value as? String)!
question.desc = (snapshot.childSnapshot(forPath: "description").value as? String)!
self.questions.append(question)
})

The only reason I'd ever consider two separate calls for title and description is if your questions contain a lot more data that you don't need here. But if that's the case, I'd remodel your JSON to separate the title and description into a separate top-level list.

In NoSQL it's often a Good Thing (tm) to model your data to be very similar to what you show on the screen. So if you have a list if the title and description of each question, you should consider storing precisely that: a list of the the title and description for each question.

How to handle asynchronous Database with Firebase?

Change this:

   myReff.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {

//this will be executed only if my array is changed (So only if my other function have been correctly executed
setAnotherArray(array_from_database);
System.out.println("3");
}

to this:

final FirebaseDatabase database = FirebaseDatabase.getInstance();
final DatabaseReference myReff = database.getReference();

myReff.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {

DatabaseReference ref2 = database.getReference();

//Take the array from my database (gived in parameter)
final ArrayList<Integer> array = array_from_database;
System.out.println("2");

array.set(0,3);

Map<String, Object> chemainChild = new HashMap<>();
chemainChild.put("server/user/",array);

myReff.updateChildren(chemainChild);

System.out.println("3");
}

Some code may be missing from the above, but you get the idea add the code that is in the method public void setArray_for_database(ArrayList<Integer> array_from_database){ for this to work.

Since onDataChange is asynchronous meaning the program will keep executing, even if data is still not retrieved then this is the only way.

The reason you get 1-3-2, is because of this:

  1. It entered the first onDataChange
  2. It printed "1"
  3. It entered the second onDataChange that is inside the first.
  4. It printed "3" since it is asynchronous, then when the data was retrieved
  5. It called the method and printed "2"

So the best thing is to add the data in the method inside the onDataChange

The above will fix the asynchronous problem that you had in the question. But you really should denormalize your data.

Read this to learn more: https://firebase.googleblog.com/2013/04/denormalizing-your-data-is-normal.html

How to query firebase and output asynchronous results?

It's not a good idea to use async/await within a forEach loop, see here and Using async/await with a forEach loop.

You should use Promise.all() as follows:

    const crawlJobIDs = projectData.crawlJobs;

let scrapeIDs = [];

let promises = [];

crawlJobIDs.forEach((jobID) => {
promises.push(db
.collection("scrapes")
.where("crawlJobID", "==", jobID)
.get());
});

const snapshot = await Promise.all(promises);

// snapshot is an Array of QuerySnapshots
// You need to loop on this Array

snapshot.forEach(querySnapshot => {
querySnapshot.forEach(documentSnapshot => {
scrapeIDs.push(documentSnapshot.id);
});
});

I let you managing the cases where the snapshots are empty...


Also, you could use another approach for

  if (!snapshot.empty) {
snapshot.forEach((doc) => {
projectData = doc.data();
});

status = 200;
}

Since you know that there is maximum one document in the querySnapshot (because of .limit(1)), do as follows:

  if (!snapshot.empty) {
const doc = snapshot.docs[0];
projectData = doc.data();

status = 200;
}

how to make an async call to firebase?

you never resolved your promise in pullFromFirebase method

checkout the code

pullFromFirebase = (displayedUser) => 
{
return new Promise((resolve, reject) =>
{
firebase.database().ref('users/' + displayedUser.id + '/usersLiked/').once('value').then(function (snapshot)
{
const users = Object.keys(snapshot.val()).map(function (key) {
return snapshot.val()[key];
})

resolve(users); // <--- here is the fix
});
})
}


Related Topics



Leave a reply



Submit