Home > Software design >  Limiting data based on document field in Firestore
Limiting data based on document field in Firestore

Time:10-17

I am playing around with Firebase Firestore for my data needs. I have a data model where there is a collection of apples, each document representing a unique apple which has a field of type object which is essentially a map of <string, string>

Think of each apple document like:

name: "SiberianApple",
weight: "400g"
color: {
  today: "green",
  yesterday: "red", 
  tomorrow: "crimson"
}

Reading through the docs, I understood that we can query collections in various ways, but is it possible to limit the amount of information a client needs to fetch while fetching a document. Can I have a query on this field color such that it only returns

name: "SiberianApple",
weight: "400g",
color: {
   today: "green"
}

Basically something like graphql, where I can ask for what I want. Wanted to know if it's possible to query or should this field be a subcollection of this document so that I can query colors using path apples/<appleId>/colors for the subCollection?

CodePudding user response:

Cloud Firestore listeners fire on the document level. There is no way to get triggered with just particular fields in a document or split the document to get only one property. It's the entire document or nothing. So the Firestore client-side SDKs always return complete documents. Unfortunately, there is no way to request only a part of the document.

is it possible to limit the amount of information.

As said, that's not possible. What you can do, is to create another collection with documents that can only hold the fields you need. This practice is called denormalization, and it's a quite common practice when it comes to NoSQL databases.

CodePudding user response:

As Alex explained in his answer, with the Client SDKs it is not possible to get only a subset of the fields for a Document. When you fetch a Document you get it with all its fields.

However, this is possible with the Firestore REST API: With the REST API you can use a DocumentMask when you fetch one document with the get method. The DocumentMask will "restrict a get operation on a document to a subset of its fields".


For querying several documents, it is a bit different: you use the runQuery method. The request body shall contain a JSON object which has a structuredQuery property.

In turn, the StructuredQuery has a select property which contains a Projection object.

Here is an example of a a payload used when calling the runQuery method (i.e. https://firestore.googleapis.com/v1/{parent=projects/*/databases/*/documents}:runQuery):

const payloadObj = {
    structuredQuery: {
      where: {
        //  ....
      },
      orderBy: [
        {
          field: {
            fieldPath: 'name',
          },
          direction: 'ASCENDING',
        },
      ],
      from: [
        {
          collectionId: 'apples',
        },
      ],
      select: {
        fields: [
          {
            fieldPath: 'name',
          },
          {
            fieldPath: 'weight',
          },
          {
            fieldPath: 'color.today',
          },
        ],
      },
      limit: 1000,
    },
  };

As you can see in the code above, you can target only one of the properties of the color map, with fieldPath: 'color.today',


End note: The REST API is less user friendly than the client SDKs because you need to build the payload passed to the request and parse the responses but it is not difficult to use. In a web app, use fetch, axios or gaxios to execute the calls.

  • Related