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

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 parameter project 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 parameter keyfile 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.

Yields:

Returns:

  • (Google::Cloud::Config)

    The configuration object the Google::Cloud::Firestore library uses.



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.

Examples:

require "google/cloud/firestore"

firestore = Google::Cloud::Firestore.new

Parameters:

  • project_id (String)

    Identifier for a Firestore project. If not present, the default project for the credentials is 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)

  • scope (String, Array<String>)

    The OAuth 2.0 scopes controlling the set of resources and operations that the connection can access. See Using OAuth 2.0 to Access Google APIs.

    The default scope is:

    • https://www.googleapis.com/auth/datastore
  • timeout (Integer)

    Default timeout to use in requests. Optional.

  • client_config (Hash)

    A hash of values to override the default behavior of the API client. Optional.

  • project (String)

    Alias for the project_id argument. Deprecated.

  • keyfile (String)

    Alias for the credentials argument. Deprecated.

Returns:

Raises:

  • (ArgumentError)


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