Module: Google::Cloud::Firestore
- Defined in:
- lib/google/cloud/firestore.rb,
lib/google/cloud/firestore/batch.rb,
lib/google/cloud/firestore/query.rb,
lib/google/cloud/firestore/client.rb,
lib/google/cloud/firestore/convert.rb,
lib/google/cloud/firestore/service.rb,
lib/google/cloud/firestore/v1beta1.rb,
lib/google/cloud/firestore/version.rb,
lib/google/cloud/firestore/generate.rb,
lib/google/cloud/firestore/field_path.rb,
lib/google/cloud/firestore/credentials.rb,
lib/google/cloud/firestore/field_value.rb,
lib/google/cloud/firestore/transaction.rb,
lib/google/cloud/firestore/watch/order.rb,
lib/google/cloud/firestore/query_listener.rb,
lib/google/cloud/firestore/query_snapshot.rb,
lib/google/cloud/firestore/watch/listener.rb,
lib/google/cloud/firestore/commit_response.rb,
lib/google/cloud/firestore/document_change.rb,
lib/google/cloud/firestore/watch/inventory.rb,
lib/google/cloud/firestore/document_listener.rb,
lib/google/cloud/firestore/document_snapshot.rb,
lib/google/cloud/firestore/document_reference.rb,
lib/google/cloud/firestore/v1beta1/credentials.rb,
lib/google/cloud/firestore/collection_reference.rb,
lib/google/cloud/firestore/watch/enumerator_queue.rb,
lib/google/cloud/firestore/v1beta1/firestore_client.rb
Overview
Cloud Firestore
Cloud Firestore is a NoSQL document database built for automatic scaling, high performance, and ease of application development. While the Cloud Firestore interface has many of the same features as traditional databases, as a NoSQL database it differs from them in the way it describes relationships between data objects.
For more information about Cloud Firestore, read the Cloud Firestore Documentation.
The goal of google-cloud is to provide an API that is comfortable to Rubyists. Authentication is handled by #firestore. You can provide the project and credential information to connect to the Cloud Firestore service, or if you are running on Google Compute Engine this configuration is taken care of for you. You can read more about the options for connecting in the Authentication Guide.
Enabling Logging
To enable logging for this library, set the logger for the underlying
gRPC library. The
logger that you set may be a Ruby stdlib
Logger
as shown below, or a
Google::Cloud::Logging::Logger
that will write logs to Stackdriver
Logging. See
grpc/logconfig.rb
and the gRPC
spec_helper.rb
for additional information.
Configuring a Ruby stdlib logger:
require "logger"
module MyLogger
LOGGER = Logger.new $stderr, level: Logger::WARN
def logger
LOGGER
end
end
# Define a gRPC module-level logger method before grpc/logconfig.rb loads.
module GRPC
extend MyLogger
end
Adding data
Cloud Firestore stores data in Documents, which are stored in Collections. Cloud Firestore creates collections and documents implicitly the first time you add data to the document. (For more information, see Adding Data to Cloud Firestore.
To create or overwrite a single document, use Client#doc to obtain a document reference. (This does not create a document in Cloud Firestore.) Then, call DocumentReference#set to create the document or overwrite an existing document:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a document reference
nyc_ref = firestore.doc "cities/NYC"
nyc_ref.set({ name: "New York City" }) # Document created
When you use this combination of doc
and set
to create a new document,
you must specify an ID for the document. (In the example above, the ID is
"NYC".) However, if you do not have a meaningful ID for the document, you
may omit the ID from a call to CollectionReference#doc, and
Cloud Firestore will auto-generate an ID for you.
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a collection reference
cities_col = firestore.col "cities"
# Get a document reference with data
random_ref = cities_col.doc
random_ref.set({ name: "New York City" })
# The document ID is randomly generated
random_ref.document_id #=> "RANDOMID123XYZ"
You can perform both of the operations shown above, auto-generating an ID and creating the document, in a single call to CollectionReference#add.
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a collection reference
cities_col = firestore.col "cities"
# Get a document reference with data
random_ref = cities_col.add({ name: "New York City" })
# The document ID is randomly generated
random_ref.document_id #=> "RANDOMID123XYZ"
You can also use add
to create an empty document:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a collection reference
cities_col = firestore.col "cities"
# Create a document without data
random_ref = cities_col.add
# The document ID is randomly generated
random_ref.document_id #=> "RANDOMID123XYZ"
Retrieving collection references
Collections are simply named containers for documents. A collection contains documents and nothing else. It can't directly contain raw fields with values, and it can't contain other collections. You do not need to "create" or "delete" collections. After you create the first document in a collection, the collection exists. If you delete all of the documents in a collection, it no longer exists. (For more information, see Cloud Firestore Data Model.
Use Client#cols to list the root-level collections:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get the root collections
firestore.cols.each do |col|
puts col.collection_id
end
Retrieving a reference to a single root-level collection is similar:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get the cities collection
cities_col = firestore.col "cities"
To list the collections in a document, first get the document reference, then use DocumentReference#cols:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a document reference
nyc_ref = firestore.doc "cities/NYC"
nyc_ref.cols.each do |col|
puts col.collection_id
end
Again, retrieving a reference to a single collection is similar::
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a document reference
nyc_ref = firestore.doc "cities/NYC"
# Get precincts sub-collection
precincts_col = nyc_ref.col "precincts"
Reading data
You can retrieve a snapshot of the data in a single document with DocumentReference#get, which returns an instance of DocumentSnapshot:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a document reference
nyc_ref = firestore.doc "cities/NYC"
nyc_snap = nyc_ref.get
nyc_snap[:population] #=> 1000000
In the example above, DocumentSnapshot#[] is used to access a top-level field. To access nested fields, use FieldPath:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
user_snap = firestore.doc("users/frank").get
nested_field_path = firestore.field_path :favorites, :food
user_snap.get(nested_field_path) #=> "Pizza"
Or, use Client#get_all to retrieve a list of document snapshots (data):
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get and print city documents
cities = ["cities/NYC", "cities/SF", "cities/LA"]
firestore.get_all(cities).each do |city|
puts "#{city.document_id} has #{city[:population]} residents."
end
To retrieve all of the document snapshots in a collection, use Query#get:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a collection reference
cities_col = firestore.col "cities"
# Get and print all city documents
cities_col.get do |city|
puts "#{city.document_id} has #{city[:population]} residents."
end
The example above is actually a simple query without filters. Let's look at some other queries for Cloud Firestore.
Querying data
Use Query#where to filter queries on a field:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a collection reference
cities_col = firestore.col "cities"
# Create a query
query = cities_col.where(:population, :>=, 1000000)
query.get do |city|
puts "#{city.document_id} has #{city[:population]} residents."
end
You can order the query results with Query#order:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a collection reference
cities_col = firestore.col "cities"
# Create a query
query = cities_col.order(:name, :desc)
query.get do |city|
puts "#{city.document_id} has #{city[:population]} residents."
end
Query methods may be chained, as in this example using Query#limit and Query#offset to perform pagination:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a collection reference
cities_col = firestore.col "cities"
# Create a query
query = cities_col.limit(5).offset(10)
query.get do |city|
puts "#{city.document_id} has #{city[:population]} residents."
end
See Managing Indexes in Cloud Firestore to ensure the best performance for your queries.
Updating data
You can use DocumentReference#set to completely overwrite an existing document:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a document reference
nyc_ref = firestore.doc "cities/NYC"
nyc_ref.set({ name: "New York City" })
Or, to selectively update only the fields appearing in your data
argument, set the merge
option to true
:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a document reference
nyc_ref = firestore.doc "cities/NYC"
nyc_ref.set({ name: "New York City" }, merge: true)
Use DocumentReference#update to directly update a deeply-nested field with a FieldPath:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
user_ref = firestore.doc "users/frank"
nested_field_path = firestore.field_path :favorites, :food
user_ref.update({ nested_field_path => "Pasta" })
Listening for changes
You can listen to a document reference or a collection reference/query for changes. The current document snapshot or query results snapshot will be yielded first, and each time the contents change.
You can use DocumentReference#listen to be notified of changes to a single document:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a document reference
nyc_ref = firestore.doc "cities/NYC"
listener = nyc_ref.listen do |snapshot|
puts "The population of #{snapshot[:name]} "
puts "is #{snapshot[:population]}."
end
# When ready, stop the listen operation and close the stream.
listener.stop
You can use Query#listen to be notified of changes to any document contained in the query:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Create a query
query = firestore.col(:cities).order(:population, :desc)
listener = query.listen do |snapshot|
puts "The query snapshot has #{snapshot.docs.count} documents "
puts "and has #{snapshot.changes.count} changes."
end
# When ready, stop the listen operation and close the stream.
listener.stop
Using transactions and batched writes
Cloud Firestore supports atomic operations for reading and writing data. In a set of atomic operations, either all of the operations succeed, or none of them are applied. There are two types of atomic operations in Cloud Firestore: A transaction is a set of read and write operations on one or more documents, while a batched write is a set of only write operations on one or more documents. (For more information, see Transactions and Batched Writes.
Transactions
A transaction consists of any number of read operations followed by any number of write operations. (Read operations must always come before write operations.) In the case of a concurrent update by another client, Cloud Firestore runs the entire transaction again. Therefore, transaction blocks should be idempotent and should not not directly modify application state.
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
city = firestore.col("cities").doc("SF")
city.set({ name: "San Francisco",
state: "CA",
country: "USA",
capital: false,
population: 860000 })
firestore.transaction do |tx|
new_population = tx.get(city).data[:population] + 1
tx.update(city, { population: new_population })
end
Batched writes
If you do not need to read any documents in your operation set, you can execute multiple write operations as a single batch. A batch of writes completes atomically and can write to multiple documents. Batched writes are also useful for migrating large data sets to Cloud Firestore.
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
firestore.batch do |b|
# Set the data for NYC
b.set("cities/NYC", { name: "New York City" })
# Update the population for SF
b.update("cities/SF", { population: 1000000 })
# Delete LA
b.delete("cities/LA")
end
Deleting data
Use DocumentReference#delete to delete a document from Cloud Firestore:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a document reference
nyc_ref = firestore.doc "cities/NYC"
nyc_ref.delete
To delete specific fields from a document, use the Client#field_delete method when you update a document:
require "google/cloud/firestore"
firestore = Google::Cloud::Firestore.new
# Get a document reference
nyc_ref = firestore.doc "cities/NYC"
nyc_ref.update({ name: "New York City",
trash: firestore.field_delete })
To delete an entire collection or sub-collection in Cloud Firestore, retrieve all the documents within the collection or sub-collection and delete them. If you have larger collections, you may want to delete the documents in smaller batches to avoid out-of-memory errors. Repeat the process until you've deleted the entire collection or sub-collection.
Defined Under Namespace
Modules: V1beta1 Classes: Batch, Client, CollectionReference, CommitResponse, Credentials, DocumentChange, DocumentListener, DocumentReference, DocumentSnapshot, FieldPath, FieldValue, Query, QueryListener, QuerySnapshot, Transaction
Constant Summary collapse
- VERSION =
"0.23.0".freeze
Class Method Summary collapse
-
.configure {|Google::Cloud.configure.firestore| ... } ⇒ Google::Cloud::Config
Configure the Google Cloud Firestore library.
-
.new(project_id: nil, credentials: nil, scope: nil, timeout: nil, client_config: nil, project: nil, keyfile: nil) ⇒ Google::Cloud::Firestore::Client
Creates a new object for connecting to the Firestore service.
Class Method Details
.configure {|Google::Cloud.configure.firestore| ... } ⇒ Google::Cloud::Config
Configure the Google Cloud Firestore library.
The following Firestore configuration parameters are supported:
project_id
- (String) Identifier for a Firestore project. (The parameterproject
is considered deprecated, but may also be used.)credentials
- (String, Hash, Google::Auth::Credentials) The path to the keyfile as a String, the contents of the keyfile as a Hash, or a Google::Auth::Credentials object. (See Credentials) (The parameterkeyfile
is considered deprecated, but may also be used.)scope
- (String, Array) The OAuth 2.0 scopes controlling the set of resources and operations that the connection can access. timeout
- (Integer) Default timeout to use in requests.client_config
- (Hash) A hash of values to override the default behavior of the API client.
615 616 617 618 619 |
# File 'lib/google/cloud/firestore.rb', line 615 def self.configure yield Google::Cloud.configure.firestore if block_given? Google::Cloud.configure.firestore end |
.new(project_id: nil, credentials: nil, scope: nil, timeout: nil, client_config: nil, project: nil, keyfile: nil) ⇒ Google::Cloud::Firestore::Client
Creates a new object for connecting to the Firestore service. Each call creates a new connection.
For more information on connecting to Google Cloud see the Authentication Guide.
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
# File 'lib/google/cloud/firestore.rb', line 572 def self.new project_id: nil, credentials: nil, scope: nil, timeout: nil, client_config: nil, project: nil, keyfile: nil project_id ||= (project || default_project_id) project_id = project_id.to_s # Always cast to a string raise ArgumentError, "project_id is missing" if project_id.empty? scope ||= configure.scope timeout ||= configure.timeout client_config ||= configure.client_config credentials ||= (keyfile || default_credentials(scope: scope)) unless credentials.is_a? Google::Auth::Credentials credentials = Firestore::Credentials.new credentials, scope: scope end Firestore::Client.new( Firestore::Service.new( project_id, credentials, timeout: timeout, client_config: client_config ) ) end |