Standard and Enterprise editions
Firestore databases come in two editions, Standard and Enterprise. The library supports both, and some features need Enterprise. Every page of this book applies to both editions, unless its title, or the part of the book it sits in, names one edition, or a section “On the Enterprise edition” lists what differs.
The edition belongs to a database, not to the project: one project can hold databases of both editions, and the client picks one by its ID, see Client instance and lifecycle.
What each edition runs
The API column names the API a row is about: Core queries, pipelines, SQL, Admin for index management, TTL and bulk delete, or Any for a row that belongs to no one API. “Pipeline, SQL” marks a row where both behave the same. A number points to the notes under the table.
| Feature | API | Standard | Enterprise |
|---|---|---|---|
| Reads and queries | Core | yes | yes |
| Reads and queries | Pipeline, SQL | fails1 | yes |
| Writes and batch writes | Core | yes | yes |
| Writes | Pipeline, SQL | no | yes |
| Query that no index covers | Core | fails2 | table scan3 |
| Query that no index covers | Pipeline, SQL | no | table scan4 |
| Aggregations: count, sum, avg | Core | yes | yes, same results |
| Transactions | Any | yes | yes5 |
| Query plans | Core | .explain() | rejected6 |
| Query plans | Pipeline, SQL | no | .explain()6 |
| Vector search | Core | needs a vector index7 | no index needed8 |
| Vector search | Pipeline | no | table scan9 |
| Text and geo search | Pipeline, SQL | no | needs a search index |
| Listeners | Core | yes | needs real-time updates |
| Caching | Core | yes | needs real-time updates |
| Caching | Pipeline, SQL | only if the cache answers in full | needs real-time updates |
| Automatic single-field indexes | Admin | yes | none |
| Single-field overrides | Admin | yes | none10 |
| Composite index of one field | Admin | a vector field only | yes |
| Unique indexes | Admin | no | yes |
| Index density11 | Admin | SparseAll only | Dense by default, or SparseAny12 |
__name__ appended to an index | Admin | yes | no |
| TTL policy | Admin | yes | yes |
| Index statements | SQL | yes | yes |
| Bulk delete | Admin | yes | yes |
| Firestore emulator | Any | the default emulator | started with --edition=enterprise |
| Billing | Any | per document read, written and deleted | read units and write units13 |
Telling which edition a database is
gcloud firestore databases describe prints the settings of a database, among them its edition,
its real-time updates mode and its concurrency mode:
gcloud firestore databases describe --database=my-database
These lines of its output name the three settings:
concurrencyMode: OPTIMISTIC
databaseEdition: ENTERPRISE
realtimeUpdatesMode: REALTIME_UPDATES_MODE_ENABLED
The Firestore page of the Google Cloud console lists the databases of a project with the edition of each.
With the admin feature, FirestoreDb::read_database_edition() returns the edition of the
database the client is connected to. A database that reports no edition reads as Standard, the
edition Firestore applies at creation. An edition this version of the crate does not know reads as
Unknown, with the value Firestore reported. Firestore may add editions, so
FirestoreDatabaseEdition is non-exhaustive. The emulator does not serve the Admin API, so the call
fails there with UNIMPLEMENTED.
use firestore::*;
async fn example(db: FirestoreDb) -> FirestoreResult<()> {
match db.read_database_edition().await? {
FirestoreDatabaseEdition::Standard => println!("Standard edition"),
FirestoreDatabaseEdition::Enterprise => println!("Enterprise edition"),
other => println!("an edition this version does not know: {other:?}"),
}
Ok(())
}
Two errors also tell the editions apart: a pipeline sent to a Standard edition database fails with
FAILED_PRECONDITION, and a Core .explain() sent to an Enterprise edition database fails with
INVALID_ARGUMENT, “Explain options are not supported in RunQuery API for Enterprise edition”.
Index management reads the edition itself, the same way, on every
.plan() and .sync(), and follows the rules of that edition.
Settings fixed at creation
The edition and the real-time updates setting are immutable: to change either, create a new database with the wanted settings and move the data. Both are chosen when the database is created:
gcloud firestore databases create --database=my-database --edition=enterprise \
--location=nam5 --enable-firestore-data-access --enable-realtime-updates
Google’s documentation does not agree on the default of real-time updates for an Enterprise
edition database, so set --enable-realtime-updates explicitly when the database needs
listeners or a
cache.
Limits
- a pipeline or SQL statement sent to a Standard edition database fails at once with
FAILED_PRECONDITION, and the library does not retry it; - a search without a search index that covers it fails with
FAILED_PRECONDITION, see Pipeline search; - joins and subqueries are in Preview, see Pipeline aggregations and joins;
- Firestore rejects an atomic pipeline or SQL write that is too big, see Write limits;
- Firestore has no setting that rejects a table scan, see Query plans and cost;
- a Core
.explain()is rejected on Enterprise. The same query written as a pipeline or SQL returns its plan through.explain(), see Explaining a pipeline.
Query and write semantics
A pipeline and a SQL statement keep Firestore’s pipeline semantics, which differ from a Core query
in a few places: not_equal matches a document that lacks the field, sort keeps such documents,
and the stages run in the order they are written.
Query and write semantics lists every difference, with the SQL spelling
of each.
Indexes
An Enterprise edition database builds no index on its own, takes indexes of one field, unique and dense indexes, and search indexes. A Standard edition database indexes every field automatically, and takes single-field overrides. See Composite and vector indexes, Search indexes and TTL and the Enterprise edition for the rules, and Waiting for changes to finish for the build times to expect on each edition.
Cost
Standard bills each document read, written and deleted; Enterprise bills read units (4 KiB) and write units (1 KiB, one more per indexed field) instead, and real-time updates as a separate charge. A read unit is 4 KiB of data, documents or index entries, that a read processes, so an Enterprise read costs by the data it scans. The rates are on Google’s pricing pages, for Standard and Enterprise. Query plans and cost shows how to read what a query costs.
Which API to use
Choosing Core queries, pipelines or SQL lists when each API fits, on each edition.
-
A pipeline or SQL statement sent to a Standard edition database fails with
FAILED_PRECONDITION, unless a cache session answers it. ↩ -
FAILED_PRECONDITION, “The query requires an index”. ↩ -
The query reads every document of the collection. Without
order_bythe order of its results is unspecified. ↩ -
A pipeline or SQL statement that no index covers runs as a table scan. A search is the exception: it needs a search index and fails without one, see Known table scans. ↩
-
Optimistic by default, so under contention more attempts abort and are retried. ↩
-
An Enterprise edition database rejects a Core
.explain()withINVALID_ARGUMENT, so explain the same query as a pipeline or SQL, see Explaining a pipeline. ↩ ↩2 -
Without a vector index the query fails with
FAILED_PRECONDITION. ↩ -
A vector index can still be created on Enterprise, but whether a Core query uses it cannot be seen, since Core
.explain()is rejected there. ↩ -
The
find_neareststage reads every document with or without a vector index, and a filter before it does not narrow the read. Google lists this as a known issue of pipelines. Use a Corefind_nearestwhere the index should be used, see Vector search. ↩ -
An
.exempt()is already satisfied. ↩ -
The density of an index is which documents it holds an entry for. ↩
-
A search index is
SparseAny. ↩ -
Real-time updates are billed separately. ↩