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.