Firestore é o banco de dados de documentos NoSQL serverless do GCP. Organiza dados em coleções e documentos JSON, com sincronização em tempo real, escalabilidade automática e sem servidor para gerenciar.
É o sucessor do Cloud Datastore e serve aplicações mobile, web e backend que precisam de esquema flexível ou sincronização ao vivo.
Modos de operação
| Modo | Quando usar |
|---|---|
| Native mode | Novos projetos: real-time listeners, SDKs Firebase, subcoleções, richer queries |
| Datastore mode | Migração de projetos legados que usavam Cloud Datastore |
Os dois modos são mutuamente exclusivos por banco. Para projetos novos, use sempre Native mode.
Modelo de dados
Database
└── Collection ("usuarios")
└── Document ("user-123")
├── Fields: string, number, boolean, timestamp, geopoint, bytes
├── Fields: map (objeto aninhado), array
└── Subcollection ("pedidos")
└── Document ("pedido-456")
Documentos têm limite de 1 MB. Subcoleções permitem hierarquia sem limite de profundidade.
{
"nome": "Logan",
"email": "[email protected]",
"criadoEm": "2026-01-15T10:00:00Z",
"endereco": {
"cidade": "São Paulo",
"estado": "SP"
},
"tags": ["admin", "ativo"],
"score": 4.8
}Operações básicas
from google.cloud import firestore
db = firestore.Client(project="meu-projeto")
# Criar / sobrescrever documento completo
db.collection("usuarios").document("user-123").set({
"nome": "Logan",
"email": "[email protected]",
"criadoEm": firestore.SERVER_TIMESTAMP
})
# Atualizar campos específicos (sem sobrescrever o resto)
db.collection("usuarios").document("user-123").update({
"nome": "Logan M.",
"endereco.cidade": "Campinas" # notação de ponto para campos aninhados
})
# Adicionar documento com ID gerado automaticamente
ref = db.collection("eventos").add({"tipo": "login", "ts": firestore.SERVER_TIMESTAMP})
print(ref[1].id) # ID gerado
# Ler documento
doc = db.collection("usuarios").document("user-123").get()
if doc.exists:
dados = doc.to_dict()
# Deletar
db.collection("usuarios").document("user-123").delete()Queries
Firestore não suporta JOINs. Queries operam em uma única coleção ou em um collection group.
# Filtros simples (requires index para combinações)
usuarios = db.collection("usuarios") \
.where(filter=firestore.FieldFilter("endereco.estado", "==", "SP")) \
.where(filter=firestore.FieldFilter("ativo", "==", True)) \
.order_by("nome") \
.limit(50) \
.stream()
for u in usuarios:
print(u.id, u.to_dict()["nome"])
# Collection group: busca em todas as subcoleções com o mesmo nome
todos_pedidos = db.collection_group("pedidos") \
.where(filter=firestore.FieldFilter("status", "==", "PENDENTE")) \
.stream()
# Operadores de array
db.collection("usuarios") \
.where(filter=firestore.FieldFilter("tags", "array_contains", "admin")) \
.stream()
# Paginação com cursor
ultimo = None # guarda o último snapshot da página anterior
pagina = db.collection("usuarios") \
.order_by("nome") \
.start_after(ultimo) \
.limit(20) \
.stream()Índices
Firestore cria índices single-field automaticamente. Para queries com múltiplos filtros ou order_by em campos diferentes, são necessários índices compostos:
# Criar índice composto via gcloud
gcloud firestore indexes composite create \
--collection-group=usuarios \
--field-config=field-path=estado,order=ASCENDING \
--field-config=field-path=criadoEm,order=DESCENDING \
--database="(default)"Ou declarar em firestore.indexes.json e fazer deploy via Firebase CLI:
{
"indexes": [
{
"collectionGroup": "usuarios",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "estado", "order": "ASCENDING" },
{ "fieldPath": "criadoEm", "order": "DESCENDING" }
]
}
]
}Transações e batch writes
# Transação (leitura + escrita atômica, com retry automático)
transaction = db.transaction()
@firestore.transactional
def transferir(transaction, origem_ref, destino_ref, valor):
origem = origem_ref.get(transaction=transaction).to_dict()
destino = destino_ref.get(transaction=transaction).to_dict()
if origem["saldo"] < valor:
raise ValueError("Saldo insuficiente")
transaction.update(origem_ref, {"saldo": firestore.Increment(-valor)})
transaction.update(destino_ref, {"saldo": firestore.Increment(valor)})
transferir(transaction,
db.document("contas/A"),
db.document("contas/B"),
100)
# Batch write (escritas atômicas sem leitura, até 500 operações)
batch = db.batch()
batch.set(db.collection("logs").document(), {
"evento": "login",
"ts": firestore.SERVER_TIMESTAMP
})
batch.update(db.document("usuarios/user-123"), {
"ultimoLogin": firestore.SERVER_TIMESTAMP,
"loginCount": firestore.Increment(1)
})
batch.commit()Real-time listeners (Native mode)
# Escutar mudanças em tempo real em uma coleção
def on_snapshot(col_snapshot, changes, read_time):
for change in changes:
if change.type.name == "ADDED":
print(f"Novo documento: {change.document.id}")
elif change.type.name == "MODIFIED":
print(f"Modificado: {change.document.id}")
elif change.type.name == "REMOVED":
print(f"Removido: {change.document.id}")
# Ouvir apenas pedidos pendentes
unsubscribe = db.collection("pedidos") \
.where(filter=firestore.FieldFilter("status", "==", "NOVO")) \
.on_snapshot(on_snapshot)
# Para parar de ouvir
unsubscribe()Precificação
Sem custo por instância; paga apenas pelo uso:
| Operação | Preço aproximado |
|---|---|
| Leitura de documento | $0.06 por 100k |
| Escrita de documento | $0.18 por 100k |
| Exclusão de documento | $0.02 por 100k |
| Storage | $0.18/GB/mês |
| Quota gratuita | 50k leituras + 20k escritas + 20k exclusões por dia |
Limitações importantes
- 1 escrita/segundo por documento: contadores de alta frequência precisam de sharding ou usar
Increment()com cuidado - Máximo 1 MB por documento
- Sem JOINs entre coleções
- Sem queries de “full-text search” (use Algolia, Elasticsearch ou BigQuery para isso)
- Máximo 500 operações por batch/transação
Emulador local
# Instalar e iniciar emulador
gcloud emulators firestore start --host-port=localhost:8080
# Configurar SDK para usar emulador
export FIRESTORE_EMULATOR_HOST="localhost:8080"
# Python usa automaticamente o emulador quando a variável está definida
db = firestore.Client(project="projeto-local")Ver também: gcp | gcp-cloud-functions | gcp-pubsub | gcp-bigtable | db-tipos-de-bancos-de-dados | db-nosql