Home > Enterprise >  How to know when all initial data is fetched from a root node using listeners in Realtime Firebase d
How to know when all initial data is fetched from a root node using listeners in Realtime Firebase d

Time:09-21

Goal:

My goal here is to fetch initial data, update UI after I am sure all data is fetched, and continue observing changes immediately:

The Problem

I see two ways to do this:

  1. To use getData method and to fetch all data at once (bulky). This is ok cause I know I have fetched all data at once, and I can accordingly update UI and continue listening for changes (CRUD).

The problem with this approach is that I can't just attach listener after, to listen to a for new additions (inserts), and wait for new items. It works differently (which makes sense cause I fetched data without being in sync with a database through listeners), and immediately after I attach the listener, I get its callback triggered as many times as how many items are currently in a root node. So I am getting most likely the same data.

So this seems like overkill.

  1. Second way to do this, is just to attach the listener, and get all data. But the problem with this is that I don't know when all data is fetched, cause it comes sequentially, one item by another. Thus I can't update UI accordingly.

Here are some code examples:

I am currently fetching all previous data with a getData method, like this:

func getInitialData(completion: @escaping DataReadCompletionHandler){
        
        rootNodeReference.getData { optionalError, snapshot in
            if let error = optionalError {
                completion([])
                return
            }
            if let value = snapshot.value,
               let models = self.parseData(type: [MyModel].self, data: value) as? [MyModel]{
                
                completion([MyModel](models.values))
            }
        }
    }

As I said, with this, I am sure I have all previous data and I can set up my UI accordingly.

After this, I am interested in only new updates (updates, deletions, inserts).

And later I connect through listeners. Here is an example for a listener that listens when something new is added to a root node:

rootNodeReference.observe(DataEventType.childAdded, with: {[weak self] snapshot in
            guard let `self` = self else {return}
            
            if let value = snapshot.value,
               let model = self.parseData(type: MyModel.self, data: value) as? MyModel{
                self.firebaseReadDelegate?.event(type: .childAdded, model: model)
            }
        }) 

This would be great if with this listener I would somehow be able to continue only updates when something new is added.

Though, I guess option 2. would be a better way to go, but how to know when I have got all data through listeners?

CodePudding user response:

There are two ways to do this, but they both depend on the same guarantee that Firebase makes about the order in which events are fired.

When you observe both child events and value events on the same path/query, the value event fires after all corresponding child events.

Because if this guarantee, you can add an additional listener to .value

rootNodeReference.observeSingleEvent(of: DataEventType.value, with: { snapshot in
  ... the initial data is all loaded
})

Adding the second listener doesn't increase the amount of data that is read from the database, because Firebase deduplicates them behind the scenese.


You can also forego the childAdded listener and just use a single observe(.value as shown in the documentation on reading a list by observing value events:

rootNodeReference.observe(.value) { snapshot in
  for child in snapshot.children {
    ...
  }
}
  • Related