Search code examples
javascriptfirebasegoogle-cloud-firestore

Firestore - can I query for one doc with parameter other than ID?


I'm coming from MongoDB and I'm struggling to understand getDoc() and getDocs().

Do I understand this correctly?

Does getDoc() only accept the document's ID as a parameter? Or can I do a query?

In the documentation I can only find code like this:

const docRef = doc(db, "collection", "11aa22bb33ccc");
const myDoc = await getDoc(docRef);

But what if I don't know the ID or I want to search with a different parameter, such as a field called author? Is it correct that I would not be able to do that with getDoc()?

With MongoDB, I can do db.collection.findOne({ author: "jones" }).

Can I not do that with Firestore?

So if I want to use a query, do I always need to use getDocs()?

If that is the case, I know that I can use limit(1) but handling the response to retrieve that one document feels not-as-smooth-as-mongodb.

I tried this:

const documents = collection(firebaseDb, 'documents');
const query = query(documents, where('author', '==', 'jones'));
const authorDocs = await getDocs(query, limit(1));
console.log(authorDocs[0].data());

And I got an error: Cannot read properties of undefined (reading 'data')

So I think I have to use a forEach, like this:

authorDocs.forEach(doc => console.log( doc.data() ));

But, for only one document? That seems odd. Is there a better way?


Solution

  • Does getDoc() only accept the document's ID as a parameter?

    No, getDoc() requires an argument of type document reference that points to a document that exists in a Firestore collection.

    But what if I don't know the ID or I want to search with a different parameter, such as a field called author?

    Then indeed you need to use a query that looks like this:

    const queryByAuthor = query(collection(db, "documents"), where("author", "==", "jones"));
    

    Is it correct that I would not be able to do that with getDoc()?

    Yes, getDoc() is used to read a single document and not multiple documents that a query returns. If you want to read all documents then indeed you need to use getDocs() and loop over the results:

    const querySnapshot = await getDocs(queryByAuthor);
    querySnapshot.forEach((doc) => {
      // doc.data() is never undefined for query doc snapshots
      console.log(doc.id, " => ", doc.data());
    });
    

    If you only want to read the first document, then you should read the document at index 0, querySnapshot[0]:

    const querySnapshot = await getDocs(queryByAuthor);
    if (querySnapshot.docs.length > 0) {
      const doc = querySnapshot.docs[0];
      console.log('Document data:', doc.data());
    }
    

    Besides that, always be sure to not use undefined objects to create references or Firestore queries.