1
votes

I have web app to get realtime updates of documents from a collection. But the collection size is too high. So getting data without applying limit not possible and not effective. So it is very important to implement some limit on query. Right now i am taking the data as a chunk of 50. I have gone trough the reference Firestore reactive pagination . The logic explained in this link working in good manner.

But there is a confusion in below code that how the document read will be calculated here. Because according to the code first i am getting documents using normal get() method as a chunk of 50 documents.After that i am attaching a listener to the response from the get() method.So will Firestore add extra 50 reads or just 50?

Here is the code what i have done

var messages = [] 
var listeners = []    // list of listeners
var start = null      // start position of listener
var end = null        // end position of listener

function getMessages(chatId) {

// query reference for the messages we want

let ref = db.collection('chats').doc(chatId)
.collection('messages')

// single query to get startAt snapshot

ref.orderBy('createdAt', 'desc')
.limit(50).get()
.then((snapshots) => {

// save startAt snapshot

start = snapshots.docs[snapshots.docs.length - 1]

// create listener using startAt snapshot (starting boundary)

let listener = ref.orderBy('createdAt')
  .startAt(start)
  .onSnapshot((messages) => {
    // append new messages to message array
    messages.forEach((message) => {
      // filter out any duplicates (from modify/delete events)         
      messages = messages.filter(x => x.id !== message.id)
      messages.push(message.data())
    })
  })

  // add listener to list

  listeners.push(listener)
})
}


 function getMoreMessages(chatId) {

let ref = db.collection('chats').doc(chatId)
.collection('messages')

// single query to get new startAt snapshot

ref.orderBy('createdAt', 'desc')
.startAt(start)
.limit(50).get()
.then((snapshots) => {

 // previous starting boundary becomes new ending boundary

  end = start
  start = snapshots.docs[snapshots.docs.length - 1]

  // create another listener using new boundaries     

  let listener = ref.orderBy('createdAt')
  .startAt(start).endBefore(end)
  .onSnapshot((messages) => {
    messages.forEach((message) => {
      messages = messages.filter(x => x.id !== message.id)
      messages.push(message.data())
    })
  })
  listeners.push(listener)
})
}

// call to detach all listeners
function detachListeners() {
 listeners.forEach(listener => listener())
 }
1

1 Answers

1
votes

This will cost 50 document reads:

ref.orderBy('createdAt', 'desc').limit(50).get()

Then this will again cost at least the same number of document reads:

ref.orderBy('createdAt').startAt(start).endBefore(end).onSnapshot(...)

Or possibly more, depending on how often those documents are updated while the listener is active.

Firestore doesn't offer an easy way to do realtime updates at the same time as pagination. Custom solutions like this will be costly like this.