class Google::Cloud::Firestore::Client

# Client

The Cloud Firestore Client used is to access and manipulate the collections and documents in the Firestore database.

@example

require "google/cloud/firestore"

firestore = Google::Cloud::Firestore.new

# Get a document reference
nyc_ref = firestore.doc "cities/NYC"

firestore.batch do |b|
  b.update(nyc_ref, { name: "New York City" })
end

Attributes

service[RW]

@private The Service object.

Public Class Methods

new(service) click to toggle source

@private Creates a new Firestore Database instance.

# File lib/google/cloud/firestore/client.rb, line 55
def initialize service
  @service = service
end

Public Instance Methods

batch() { |batch| ... } click to toggle source

Perform multiple changes at the same time.

All changes are accumulated in memory until the block completes. Unlike transactions, batches don't lock on document reads, should only fail if users provide preconditions, and are not automatically retried. See {Batch}.

@see firebase.google.com/docs/firestore/manage-data/transactions

Transactions and Batched Writes

@yield [batch] The block for reading data and making changes. @yieldparam [Batch] batch The write batch object for making changes.

@return [CommitResponse] The response from committing the changes.

@example

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
# File lib/google/cloud/firestore/client.rb, line 572
def batch
  batch = Batch.from_client self
  yield batch
  batch.commit
end
col(collection_path) click to toggle source

Retrieves a collection.

@param [String] collection_path A string representing the path of the

collection, relative to the document root of the database.

@return [CollectionReference] A collection.

@example

require "google/cloud/firestore"

firestore = Google::Cloud::Firestore.new

# Get the cities collection
cities_col = firestore.col "cities"

# Get the document for NYC
nyc_ref = cities_col.doc "NYC"
# File lib/google/cloud/firestore/client.rb, line 133
def col collection_path
  if collection_path.to_s.split("/").count.even?
    raise ArgumentError, "collection_path must refer to a collection."
  end

  CollectionReference.from_path "#{path}/documents/#{collection_path}", self
end
Also aliased as: collection
col_group(collection_id) click to toggle source

Creates and returns a new collection group that includes all documents in the database that are contained in a collection or subcollection with the given collection_id.

@param [String] collection_id Identifies the collections to query

over. Every collection or subcollection with this ID as the last
segment of its path will be included. Cannot contain a slash (`/`).

@return [CollectionGroup] The created collection group.

@example

require "google/cloud/firestore"

firestore = Google::Cloud::Firestore.new

# Get the cities collection group query
col_group = firestore.col_group "cities"

col_group.get do |city|
  puts "#{city.document_id} has #{city[:population]} residents."
end
# File lib/google/cloud/firestore/client.rb, line 165
def col_group collection_id
  if collection_id.include? "/"
    raise ArgumentError, "Invalid collection_id: '#{collection_id}', " \
      "must not contain '/'."
  end

  CollectionGroup.from_collection_id service.documents_path, collection_id, self
end
Also aliased as: collection_group
collection(collection_path)
Alias for: col
collection_group(collection_id)
Alias for: col_group
collections(&block)
Alias for: cols
cols(&block) click to toggle source

Retrieves an enumerator for the root collections.

@yield [collections] The block for accessing the collections. @yieldparam [CollectionReference] collection A collection reference object.

@return [Enumerator<CollectionReference>] An enumerator of collection references. If a block is provided,

this is the same enumerator that is accessed through the block.

@example

require "google/cloud/firestore"

firestore = Google::Cloud::Firestore.new

# Get the root collections
firestore.cols.each do |col|
  puts col.collection_id
end
# File lib/google/cloud/firestore/client.rb, line 104
def cols &block
  ensure_service!
  grpc = service.list_collections "#{path}/documents"
  cols_enum = CollectionReferenceList.from_grpc(grpc, self, "#{path}/documents").all
  cols_enum.each(&block) if block_given?
  cols_enum
end
Also aliased as: collections, list_collections
database_id() click to toggle source

The database identifier for the Cloud Firestore database.

@return [String] database identifier.

# File lib/google/cloud/firestore/client.rb, line 71
def database_id
  "(default)"
end
doc(document_path) click to toggle source

Retrieves a document reference.

@param [String] document_path A string representing the path of the

document, relative to the document root of the database.

@return [DocumentReference] A document.

@example

require "google/cloud/firestore"

firestore = Google::Cloud::Firestore.new

# Get a document
nyc_ref = firestore.doc "cities/NYC"

puts nyc_ref.document_id
# File lib/google/cloud/firestore/client.rb, line 193
def doc document_path
  if document_path.to_s.split("/").count.odd?
    raise ArgumentError, "document_path must refer to a document."
  end

  doc_path = "#{path}/documents/#{document_path}"

  DocumentReference.from_path doc_path, self
end
Also aliased as: document
document(document_path)
Alias for: doc
document_id() click to toggle source

Creates a field path object representing the sentinel ID of a document. It can be used in queries to sort or filter by the document ID. See {FieldPath#document_id}.

@return [FieldPath] The field path object.

@example

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(firestore.document_id)
                  .start_at("NYC")

query.get do |city|
  puts "#{city.document_id} has #{city[:population]} residents."
end
# File lib/google/cloud/firestore/client.rb, line 301
def document_id
  FieldPath.document_id
end
field_array_delete(*values) click to toggle source

Creates a sentinel value to indicate the removal of the given values with an array.

@param [Object] values The values to remove from the array. Required.

@return [FieldValue] The array delete field value object.

@example

require "google/cloud/firestore"

firestore = Google::Cloud::Firestore.new

# Get a document reference
nyc_ref = firestore.doc "cities/NYC"

array_delete = firestore.field_array_delete 7, 8, 9

nyc_ref.update({ name: "New York City",
                 lucky_numbers: array_delete })
# File lib/google/cloud/firestore/client.rb, line 417
def field_array_delete *values
  FieldValue.array_delete(*values)
end
field_array_union(*values) click to toggle source

Creates a sentinel value to indicate the union of the given values with an array.

@param [Object] values The values to add to the array. Required.

@return [FieldValue] The array union field value object.

@example

require "google/cloud/firestore"

firestore = Google::Cloud::Firestore.new

# Get a document reference
nyc_ref = firestore.doc "cities/NYC"

array_union = firestore.field_array_union 1, 2, 3

nyc_ref.update({ name: "New York City",
                 lucky_numbers: array_union })
# File lib/google/cloud/firestore/client.rb, line 392
def field_array_union *values
  FieldValue.array_union(*values)
end
field_delete() click to toggle source

Creates a field value object representing the deletion of a field in document data.

@return [FieldValue] The delete field value object.

@example

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 })
# File lib/google/cloud/firestore/client.rb, line 346
def field_delete
  FieldValue.delete
end
field_increment(value) click to toggle source

Creates a sentinel value to indicate the addition the given value to the field's current value.

If the field's current value is not an integer or a double value (Numeric), or if the field does not yet exist, the transformation will set the field to the given value. If either of the given value or the current field value are doubles, both values will be interpreted as doubles. Double arithmetic and representation of double values follow IEEE 754 semantics. If there is positive/negative integer overflow, the field is resolved to the largest magnitude positive/negative integer.

@param [Numeric] value The value to add to the given value. Required.

@return [FieldValue] The increment field value object.

@raise [ArgumentError] if the value is not a Numeric.

@example

require "google/cloud/firestore"

firestore = Google::Cloud::Firestore.new

# Get a document reference
nyc_ref = firestore.doc "cities/NYC"

# Set the population to increment by 1.
increment_value = firestore.field_increment 1

nyc_ref.update({ name: "New York City",
                 population: increment_value })
# File lib/google/cloud/firestore/client.rb, line 454
def field_increment value
  FieldValue.increment value
end
field_maximum(value) click to toggle source

Creates a sentinel value to indicate the setting the field to the maximum of its current value and the given value.

If the field is not an integer or double (Numeric), or if the field does not yet exist, the transformation will set the field to the given value. If a maximum operation is applied where the field and the input value are of mixed types (that is - one is an integer and one is a double) the field takes on the type of the larger operand. If the operands are equivalent (e.g. 3 and 3.0), the field does not change. 0, 0.0, and -0.0 are all zero. The maximum of a zero stored value and zero input value is always the stored value. The maximum of any numeric value x and NaN is NaN.

@param [Numeric] value The value to compare against the given value to

calculate the maximum value to set. Required.

@return [FieldValue] The maximum field value object.

@raise [ArgumentError] if the value is not a Numeric.

@example

require "google/cloud/firestore"

firestore = Google::Cloud::Firestore.new

# Get a document reference
nyc_ref = firestore.doc "cities/NYC"

# Set the population to be at maximum 4,000,000.
maximum_value = firestore.field_maximum 4000000

nyc_ref.update({ name: "New York City",
                 population: maximum_value })
# File lib/google/cloud/firestore/client.rb, line 493
def field_maximum value
  FieldValue.maximum value
end
field_minimum(value) click to toggle source

Creates a sentinel value to indicate the setting the field to the minimum of its current value and the given value.

If the field is not an integer or double (Numeric), or if the field does not yet exist, the transformation will set the field to the input value. If a minimum operation is applied where the field and the input value are of mixed types (that is - one is an integer and one is a double) the field takes on the type of the smaller operand. If the operands are equivalent (e.g. 3 and 3.0), the field does not change. 0, 0.0, and -0.0 are all zero. The minimum of a zero stored value and zero input value is always the stored value. The minimum of any numeric value x and NaN is NaN.

@param [Numeric] value The value to compare against the given value to

calculate the minimum value to set. Required.

@return [FieldValue] The minimum field value object.

@raise [ArgumentError] if the value is not a Numeric.

@example

require "google/cloud/firestore"

firestore = Google::Cloud::Firestore.new

# Get a document reference
nyc_ref = firestore.doc "cities/NYC"

# Set the population to be at minimum 1,000,000.
minimum_value = firestore.field_minimum 1000000

nyc_ref.update({ name: "New York City",
                 population: minimum_value })
# File lib/google/cloud/firestore/client.rb, line 532
def field_minimum value
  FieldValue.minimum value
end
field_path(*fields) click to toggle source

Creates a field path object representing a nested field for document data.

@param [String, Symbol, Array<String|Symbol>] fields One or more

strings representing the path of the data to select. Each field must
be provided separately.

@return [FieldPath] The field path object.

@example

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"
# File lib/google/cloud/firestore/client.rb, line 325
def field_path *fields
  FieldPath.new(*fields)
end
field_server_time() click to toggle source

Creates a field value object representing set a field's value to the server timestamp when accessing the document data.

@return [FieldValue] The server time field value object.

@example

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",
                 updated_at: firestore.field_server_time })
# File lib/google/cloud/firestore/client.rb, line 367
def field_server_time
  FieldValue.server_time
end
find(*docs, field_mask: nil)
Alias for: get_all
get_all(*docs, field_mask: nil) { |from_batch_result result, self| ... } click to toggle source

Retrieves a list of document snapshots.

@param [String, DocumentReference, Array<String|DocumentReference>]

docs One or more strings representing the path of the document, or
document reference objects.

@param [Array<String|FieldPath>] field_mask One or more field path

values, representing the fields of the document to be returned. If a
document has a field that is not present in this mask, that field
will not be returned in the response. All fields are returned when
the mask is not set.

A field path can either be a {FieldPath} object, or a dotted string
representing the nested fields. In other words the string represents
individual fields joined by ".". Fields containing `~`, `*`, `/`,
`[`, `]`, and `.` cannot be in a dotted string, and should provided
using a {FieldPath} object instead. (See {#field_path}.)

@yield [documents] The block for accessing the document snapshots. @yieldparam [DocumentSnapshot] document A document snapshot.

@return [Enumerator<DocumentSnapshot>] document snapshots list.

@example

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

@example Get docs using a field mask:

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, field_mask: [:population]).each do |city|
  puts "#{city.document_id} has #{city[:population]} residents."
end
# File lib/google/cloud/firestore/client.rb, line 249
def get_all *docs, field_mask: nil
  ensure_service!

  unless block_given?
    return enum_for :get_all, *docs, field_mask: field_mask
  end

  doc_paths = Array(docs).flatten.map do |doc_path|
    coalesce_doc_path_argument doc_path
  end
  mask = Array(field_mask).map do |field_path|
    if field_path.is_a? FieldPath
      field_path.formatted_string
    else
      FieldPath.parse(field_path).formatted_string
    end
  end
  mask = nil if mask.empty?

  results = service.get_documents doc_paths, mask: mask
  results.each do |result|
    next if result.result.nil?
    yield DocumentSnapshot.from_batch_result result, self
  end
end
Also aliased as: get_docs, get_documents, find
get_docs(*docs, field_mask: nil)
Alias for: get_all
get_documents(*docs, field_mask: nil)
Alias for: get_all
list_collections(&block)
Alias for: cols
list_documents(parent, collection_id, token: nil, max: nil) click to toggle source

@private

# File lib/google/cloud/firestore/client.rb, line 675
def list_documents parent, collection_id, token: nil, max: nil
  ensure_service!
  grpc = service.list_documents parent, collection_id, token: token, max: max
  DocumentReference::List.from_grpc grpc, self, parent, collection_id
end
path() click to toggle source

@private The full Database path for the Cloud Firestore database.

@return [String] database resource path.

# File lib/google/cloud/firestore/client.rb, line 79
def path
  service.database_path
end
project_id() click to toggle source

The project identifier for the Cloud Firestore database.

@return [String] project identifier.

# File lib/google/cloud/firestore/client.rb, line 63
def project_id
  service.project
end
transaction(max_retries: nil, commit_response: nil) { |transaction| ... } click to toggle source

Create a transaction to perform multiple reads and writes that are executed atomically at a single logical point in time in a database.

All changes are accumulated in memory until the block completes. Transactions will be automatically retried when documents change before the transaction is committed. See {Transaction}.

@see firebase.google.com/docs/firestore/manage-data/transactions

Transactions and Batched Writes

@param [Integer] max_retries The maximum number of retries for

transactions failed due to errors. Default is 5. Optional.

@param [Boolean] commit_response When `true`, the return value from

this method will be a `Google::Cloud::Firestore::CommitResponse`
object with a `commit_time` attribute. Otherwise, the return
value from this method will be the return value of the provided
yield block. Default is `false`. Optional.

@yield [transaction] The block for reading data and making changes. @yieldparam [Transaction] transaction The transaction object for

making changes.

@return [Object, CommitResponse] The return value of the provided

yield block, or if `commit_response` is provided and true, the
`CommitResponse` object from the commit operation.

@example

require "google/cloud/firestore"

firestore = Google::Cloud::Firestore.new

firestore.transaction do |tx|
  # Set the data for NYC
  tx.set("cities/NYC", { name: "New York City" })

  # Update the population for SF
  tx.update("cities/SF", { population: 1000000 })

  # Delete LA
  tx.delete("cities/LA")
end
# File lib/google/cloud/firestore/client.rb, line 621
def transaction max_retries: nil, commit_response: nil
  max_retries = 5 unless max_retries.is_a? Integer
  backoff = { current: 0, delay: 1.0, max: max_retries, mod: 1.3 }

  transaction = Transaction.from_client self
  begin
    transaction_return = yield transaction
    commit_return = transaction.commit
    # Conditional return value, depending on truthy commit_response
    commit_response ? commit_return : transaction_return
  rescue Google::Cloud::AbortedError,
         Google::Cloud::CanceledError,
         Google::Cloud::UnknownError,
         Google::Cloud::DeadlineExceededError,
         Google::Cloud::InternalError,
         Google::Cloud::UnauthenticatedError,
         Google::Cloud::ResourceExhaustedError,
         Google::Cloud::UnavailableError,
         Google::Cloud::InvalidArgumentError => e

    if e.instance_of? Google::Cloud::InvalidArgumentError
      # Return if a previous call was retried but ultimately succeeded
      return nil if backoff[:current].positive?
      # The Firestore backend uses "INVALID_ARGUMENT" for transaction IDs that have expired.
      # While INVALID_ARGUMENT is generally not retryable, we retry this specific case.
      raise e unless e.message =~ /transaction has expired/
    end

    # Re-raise if retried more than the max
    raise e if backoff[:current] > backoff[:max]

    # Sleep with incremental backoff before restarting
    sleep backoff[:delay]

    # Update increment backoff delay and retry counter
    backoff[:delay] *= backoff[:mod]
    backoff[:current] += 1

    # Create new transaction and retry
    transaction = Transaction.from_client \
      self, previous_transaction: transaction.transaction_id
    retry
  rescue StandardError => e
    # Rollback transaction when handling unexpected error
    transaction.rollback rescue nil

    # Re-raise error.
    raise e
  end
end

Protected Instance Methods

coalesce_doc_path_argument(doc_path) click to toggle source

@private

# File lib/google/cloud/firestore/client.rb, line 697
def coalesce_doc_path_argument doc_path
  return doc_path.path if doc_path.respond_to? :path

  doc(doc_path).path
end
coalesce_get_argument(obj) click to toggle source

@private

# File lib/google/cloud/firestore/client.rb, line 685
def coalesce_get_argument obj
  return obj.ref if obj.is_a? DocumentSnapshot

  return obj unless obj.is_a?(String) || obj.is_a?(Symbol)

  return doc obj if obj.to_s.split("/").count.even?

  col obj # Convert to CollectionReference
end
ensure_service!() click to toggle source

@private Raise an error unless an active connection to the service is available.

# File lib/google/cloud/firestore/client.rb, line 706
def ensure_service!
  raise "Must have active connection to service" unless service
end