0

I already read few post on the topic, but for some reason I can not fetch the docs which I need. I have a collection users with auto generated id and each doc contains name and email. Here is my collection: enter image description here

Please note, the ids are auto generated.

Then, what I try to do in the code is the following:

firebase.firestore()
        .collection("users")
        .where(
          "id",
          "in",
          ids
        )
        .get()
        .then((querySnapshot) => {
            const people = [];
            querySnapshot.forEach(documentSnapshot => {
              people.push({
                  ...documentSnapshot.data(),
                  key: documentSnapshot.id
                  });
                });
              console.log("people: ", people);
          });

My people arrays is empty. I am pretty sure that my ids array has the correct ids. I am not sure if this part is correct:

firebase.firestore()
        .collection("users")
        .where(
          "id",
          "in",
          ids
        )
        .get()

Is "id" the correct name of the auto generated column?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
newbie coder
  • 644
  • 5
  • 18

2 Answers2

2

To query a document by it's ID, you should make use of firebase.firestore.FieldPath.documentId() which returns a special value that can be used with the where() filter to search by a document's ID.


The following code has been tweaked from this documented gist (Typescript/JavaScript):

function chunkArr(arr, n) {
  if (n <= 0) throw new Error("n must be greater than 0");
  return Array
    .from({length: Math.ceil(arr.length/n)})
    .map((_, i) => arr.slice(n*i, n*(i+1)))
}

async function fetchDocumentsWithId(collectionQueryRef, arrayOfIds) {
  // in batches of 10, fetch the documents with the given ID from the collection
  const fetchDocsPromises = chunkArr(arrayOfIds, 10)
    .map((idsInChunk) => (
      collectionQueryRef
        .where(firebase.firestore.FieldPath.documentId(), "in", idsInChunk)
        .get()
    ))

  return Promise.all(fetchDocsPromises)
    .then((querySnapshotArray) => {
      const allDocumentsArray = [];
      for (let querySnapshot of querySnapshotArray) {
        querySnapshot.forEach(doc => allDocumentSnapshotsArray.push({...doc.data(), key: doc.id}))
      }
      return allDocumentsArray;
    });
}

const usersColRef = firebase.firestore()
        .collection("users");
const ids = [ /* ... */ ];

const docDataArray = fetchDocumentsWithId(usersColRef, ids);

If you were to use the unedited version of the gist, you would instead use:


const usersColRef = firebase.firestore()
        .collection("users");
const ids = [ /* ... */ ];
const docDataArray = [];

await fetchDocumentsWithId(usersColRef, ids, (doc) => docDataArray.push({ ...doc.data(), key: doc.id }))

console.log(docDataArray)

Note: I'd avoid using the term "key" for Firestore and instead use "id". If you are using "id" in your documents, you could always use "_id" instead.

samthecodingman
  • 23,122
  • 4
  • 30
  • 54
  • You'll want to review some limitation with the value created by firebase.firestore.FieldPath.documentId() - it returns the FULL PATH to the document, not just the specific documentId https://stackoverflow.com/a/58104104/2434784 – LeadDreamer Apr 06 '21 at 15:29
  • @LeadDreamer I'm not sure when, but that problem has been resolved since that answer was posted as the code included here works as intended. I'll see if I can find some information on when/how this was fixed which should be sometime between Jan and Jun 2020. – samthecodingman Apr 07 '21 at 03:40
  • @LeadDreamer Following up on my previous comment, there are two modes of `firebase.firestore.FieldPath.documentId()`. When used on a `CollectionReference`, you specify just the document ID (e.g. `"c90QMzGbPSJA1qiQ95f6"`). However, when used on a collection group query you specify a valid document path (e.g. `"users/Ddy1QVOAO6SIvB8LfAE8Z0Adj4H3/todos/c90QMzGbPSJA1qiQ95f6"`). This seems to be intended [based on the SDK tests](https://github.com/firebase/firebase-js-sdk/blob/5ad7ff2ae955c297556223e6cb3ad9d4b897f664/packages/firestore/test/integration/api/validation.test.ts#L766-L792). – samthecodingman Apr 07 '21 at 04:04
  • Thanks for mentioning it, and I'll make sure to update the gist with this info while the documentation on this feature is unavailable. – samthecodingman Apr 07 '21 at 04:06
-1

In this situation I am assuming that ids is an array that you have in your client side code and are looking to query only for those ids in firestore?

Unfortunately, when using the .where() functionality in firestore, it does not query against the document ID's but rather the content of the document.

If you wanted to use the .where() indexing capability of firestore, you would need to add a uid field to the actual document data. Once you do that, you should be able to query for only the ID's you would like.

From the firestore docs

cpboyce
  • 187
  • 9
  • I see. Isn't that a bad practice? I mean, I have the ids one time, and then I put them second time. Or this is a standard practice? Tbh, I can't find any "easy" way of taking the docs which are in my array, apart of for loop and querying one by one? – newbie coder Apr 06 '21 at 13:37
  • Also, am I right that the column was named "id"? – newbie coder Apr 06 '21 at 13:37
  • The denormalization (repetition) of data is not bad practice in a NoSQL data structure such as Firestore. And no, you can not query against document ids beyond `firestore.collection('users').doc()`. – cpboyce Apr 06 '21 at 13:40
  • @cpboyce While this was the case many years ago, there has been support for queries using document IDs since 2017. – samthecodingman Apr 06 '21 at 14:52
  • @samthecodingman could you provide a link to where in the documentation it mentions that? Because I have not read about that and am interested to see. – cpboyce Apr 06 '21 at 20:12
  • 1
    @cpboyce Annoyingly it's not mentioned in the [guide documentation](https://firebase.google.com/docs/firestore), but has been around since v0.1.1 of the Firestore SDK ([Release Notes](https://firebase.google.com/support/release-notes/js#version_451_-_october_12_2017)/[GitHub Changelog](https://github.com/firebase/firebase-js-sdk/blob/master/packages/firestore/CHANGELOG.md#v011)). The reason I came across it is because it was finally added to the [documented API Reference](https://firebase.google.com/docs/reference/js/firebase.firestore.FieldPath#documentid) last June. – samthecodingman Apr 07 '21 at 03:25
  • 1
    This isn't the only thing that hasn't been updated in the guides either. The guide is yet to be updated to state that batched writes don't count [field transforms as two operations anymore](https://firebase.google.com/support/release-notes/js#version_820_-_december_11_2020) – samthecodingman Apr 07 '21 at 03:28