By Joon


2017-10-13 02:18:42 8 Comments

I am wondering if it's possible to get multiple documents by list of ids in one round trip (network call) to the Firestore.

8 comments

@Markymark 2019-08-20 05:39:49

Here's how you would do something like this in Kotlin with the Android SDK.
May not necessarily be in one round trip, but it does effectively group the result and avoid many nested callbacks.

val userIds = listOf("123", "456")
val userTasks = userIds.map { firestore.document("users/${it!!}").get() }

Tasks.whenAllSuccess<DocumentSnapshot>(userTasks).addOnSuccessListener { documentList ->
    //Do what you need to with the document list
}

Note that fetching specific documents is much better than fetching all documents and filtering the result. This is because Firestore charges you for the query result set.

@Georgi 2019-09-22 13:32:34

Works nicely, exactly what I was looking for!

@JP de la Torre 2018-05-17 15:13:59

You could use a function like this:

function getById (path, ids) {
  return firestore.getAll(
    [].concat(ids).map(id => firestore.doc(`${path}/${id}`))
  )
}

It can be called with a single ID:

getById('collection', 'some_id')

or an array of IDs:

getById('collection', ['some_id', 'some_other_id'])

@Nick Franceschina 2018-01-24 13:27:07

if you're within Node:

https://github.com/googleapis/nodejs-firestore/blob/master/dev/src/index.ts#L701

/**
* Retrieves multiple documents from Firestore.
*
* @param {...DocumentReference} documents - The document references
* to receive.
* @returns {Promise<Array.<DocumentSnapshot>>} A Promise that
* contains an array with the resulting document snapshots.
*
* @example
* let documentRef1 = firestore.doc('col/doc1');
* let documentRef2 = firestore.doc('col/doc2');
*
* firestore.getAll(documentRef1, documentRef2).then(docs => {
*   console.log(`First document: ${JSON.stringify(docs[0])}`);
*   console.log(`Second document: ${JSON.stringify(docs[1])}`);
* });
*/

@Horea 2018-03-06 17:32:50

For anyone looking to call this method with a dynamically generated array of document references, you can do it like this: firestore.getAll(...arrayOfReferences).then()

@Nick Franceschina 2019-01-22 11:26:37

thanks @KamanaKisinga - fixed

@Kisinga 2019-01-23 09:56:39

@NickFranceschina do you know how to this can be used on angularfire or firebase vanilla libs?

@Nick Franceschina 2019-01-24 11:19:40

I'm sorry @KamanaKisinga ... I haven't done any firebase stuff in almost a year and can't really help at this time (hey look, I actually posted this answer one year ago today!)

@Kisinga 2019-01-24 13:31:30

@NickFranceschina 😂😂 Fair enough Thanks though

@Julian Paolo Dayag 2019-02-12 06:22:20

how about firestore.getAll.call(null, arrayOfReferences) if the spread operator is not yet supported?

@sMyles 2019-05-31 22:55:33

The issue here is that this is all SERVER based, not client based ...

@Sebastian 2018-11-27 22:07:18

In practise you would use firestore.getAll like this

async getUsers({userIds}) {
    const refs = userIds.map(id => this.firestore.doc(`users/${id}`))
    const users = await this.firestore.getAll(...refs)
    console.log(users.map(doc => doc.data()))
}

or with promise syntax

getUsers({userIds}) {
    const refs = userIds.map(id => this.firestore.doc(`users/${id}`))
    this.firestore.getAll(...refs).then(users => console.log(users.map(doc => doc.data())))
}

@Ron Royston 2018-09-17 19:29:02

The best you can do is not use Promise.all as your client then must wait for .all the reads before proceeding.

Iterate the reads and let them resolve independently. On the client side, this probably boils down to the UI having several progress loader images resolve to values independently. However, this is better than freezing the whole client until .all the reads resolve.

Therefore, dump all the synchronous results to the view immediately, then let the asynchronous results come in as they resolve, individually. This may seem like petty distinction, but if your client has poor Internet connectivity (like I currently have at this coffee shop), freezing the whole client experience for several seconds will likely result in a 'this app sucks' experience.

@Ryan Taylor 2019-03-08 19:12:17

It's asynchronous, there are plenty of use cases for using Promise.all... it doesn't necessarily have to "freeze" anything – you might need to wait for all the data before you're able to do something meaningful

@schankam 2019-06-11 04:44:53

There are several use cases when you do need to load all of your data, therefore the wait (like a spinner with an appropriate message, no need to "freeze" any UI like you say) can be totally needed by Promise.all... It just really depends on what kind of products you are building here. These kind of comments are to my own opinion very irrelevant and there shouldn't be any "best" words in it. It really depends on every different use cases one can face and what your app is doing for the user.

@Chris Wilson 2018-03-04 11:07:44

Surely the best way to do this is by implementing the actual query of Firestore in a Cloud Function? There would then only be a single round trip call from the client to Firebase, which seems to be what you're asking for.

You really want to be keeping all of your data access logic like this server side anyway.

Internally there will likely be the same number of calls to Firebase itself, but they would all be across Google's super-fast interconnects, rather than the external network, and combined with the pipelining which Frank van Puffelen has explained, you should get excellent performance from this approach.

@Jeremiah 2018-03-07 20:45:46

Storing the implementation in a Cloud Function is the right decision in some cases where you have complex logic, but probably not in the case where you just want to merge a list with multiple id's. What you lose is the client side caching and standardized return formatting from regular calls. This caused more performance issues than it solved in some cases in my apps when I used the approach.

@Horea 2017-12-23 09:26:09

This doesn't seem to be possible in Firestore at the moment. I don't understand why Alexander's answer is accepted, the solution he proposes just returns all the documents in the "users" collection.

Depending on what you need to do, you should look into duplicating the relevant data you need to display and only request a full document when needed.

@Sam Stern 2017-10-16 15:01:27

No, right now there is no way to batch multiple read requests using the Cloud Firestore SDK and therefore no way to guarantee that you can read all of the data at once.

However as Frank van Puffelen has said in the comments above this does not mean that fetching 3 documents will be 3x as slow as fetching one document. It is best to perform your own measurements before reaching a conclusion here.

@Joon 2017-10-17 02:09:25

The thing is that I want to know theoretical limits to Firestore's performance before migrating to Firestore. I don't want to migrate and then realize that it's not good enough for my use case.

@Joon 2017-10-17 02:11:10

For me, no batching support is not good. As most of my app's database calls are around getting multiple (often times hundreds) documents with multiple ids. To be performant, those calls need to be batched for me.

@Sam Stern 2017-10-17 15:08:20

@Joon it sounds like you will have to re-evaluate your data structures to be more performant in a NoSQL database like Cloud Firestore. The best advice I can give is to think backwards from queries. Think of a query you'd like to execute, and structure your data so that you can express it simply. All queries in Cloud Firestore are fast.

@Tapas Mukherjee 2017-10-25 22:02:40

Hi, there is also a considaration of cose here. Let say I have stored list of all my friend's IDs and the number is 500. I can get the list in 1 read cost but in order to display their Name and photoURL, it will cost me 500 reads.

@Frank van Puffelen 2017-10-27 05:43:58

If you're trying to read 500 documents, it takes 500 reads. If you combine the information that you need from all 500 documents into a single extra document, it only takes one read. That's called sort of data duplication is quite normal in most NoSQL database, including Cloud Firestore.

@Sitian Liu 2017-10-27 21:10:57

@FrankvanPuffelen is there seriously no other way besides what you have described as "all 500 documents into a single extra document". I am having a hard time accepting this constraint in NoSQL database. could you shine some light on some related posts or discussions on the common practices in these case? Thank you so much

@Sitian Liu 2017-10-27 21:17:57

@FrankvanPuffelen For instance, in mongoDb, you can use ObjectId like this stackoverflow.com/a/32264630/648851.

@wildcat12 2018-04-19 13:24:17

The other consideration here I think (someone from the Firestore team would need to confirm) is that if you have the data that satisfies your query cached locally, which is done automatically with Firestore, it does NOT cost 500 reads. You're only charged for reads that require getting documents/updates from the server.

@Sam Stern 2018-04-19 16:15:34

@wildcat12 right now it will cost you 500 reads because we don't specify a way to say "give me only cached data", the SDK will always follow up the cached data with a check for latest. But that's something we're working on.

@Dr. C. Hilarius 2018-12-03 18:29:00

@SamStern Is there still no support for batching queries?

@schankam 2019-06-11 05:06:21

Like @FrankvanPuffelen said, data duplication is pretty common in NoSQL database. Here you have to ask yourself how often these data are required to be read, and how up-to-date they need to be. If you do store 500 of users information, let's say their name + photo + id, you can get them in one read. But if you need them up-to-date, you'll probably have to use a cloud function to update these references each time a user update their name / photo, therefore running a cloud function + doing some write operations. There is no "right" / "better" implementation, it just depends on your use case.

Related Questions

Sponsored Content

5 Answered Questions

4 Answered Questions

[SOLVED] Firestore query documents startsWith a string

1 Answered Questions

3 Answered Questions

[SOLVED] How to create/update multiple documents at once in Firestore

5 Answered Questions

[SOLVED] Firestore - Get document collections

3 Answered Questions

4 Answered Questions

0 Answered Questions

Firestore Fetching Multiple Documents Best Practice

1 Answered Questions

1 Answered Questions

Sponsored Content