Class: Couchbase::Collection

Inherits:
Object
  • Object
show all
Defined in:
lib/couchbase/collection.rb,
lib/couchbase/collection_options.rb,
/Users/sergey.auseyau/code/couchbase-ruby-client/lib/couchbase/collection.rb,
/Users/sergey.auseyau/code/couchbase-ruby-client/lib/couchbase/collection_options.rb

Defined Under Namespace

Classes: ExistsResult, GetReplicaResult, GetResult, LookupInResult, MutateInResult, MutationResult

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(backend, bucket_name, scope_name, collection_name) ⇒ Collection

Returns a new instance of Collection.

Parameters:

  • backend (Couchbase::Backend)
  • bucket_name (String)

    name of the bucket

  • scope_name (String, :_default)

    name of the scope

  • collection_name (String, :_default)

    name of the collection



31
32
33
34
35
36
# File 'lib/couchbase/collection.rb', line 31

def initialize(backend, bucket_name, scope_name, collection_name)
  @backend = backend
  @bucket_name = bucket_name
  @scope_name = scope_name
  @name = collection_name
end

Instance Attribute Details

#bucket_nameObject (readonly)

Returns the value of attribute bucket_name.



21
22
23
# File 'lib/couchbase/collection.rb', line 21

def bucket_name
  @bucket_name
end

#nameObject (readonly)

Returns the value of attribute name.



23
24
25
# File 'lib/couchbase/collection.rb', line 23

def name
  @name
end

#scope_nameObject (readonly)

Returns the value of attribute scope_name.



22
23
24
# File 'lib/couchbase/collection.rb', line 22

def scope_name
  @scope_name
end

Instance Method Details

#binaryBinaryCollection

Provides access to the binary APIs, not used for JSON documents

Returns:



41
42
43
# File 'lib/couchbase/collection.rb', line 41

def binary
  BinaryCollection.new(self)
end

#exists(id, options = Options::Exists.new) ⇒ ExistsResult

Checks if the given document ID exists on the active partition.

Examples:

Check if the document exists without fetching its contents

res = collection.exists("customer123")
res.exists? #=> true

Parameters:

  • id (String)

    the document id which is used to uniquely identify it.

  • options (Options::Exists) (defaults to: Options::Exists.new)

    request customization

Returns:



190
191
192
193
194
195
196
197
# File 'lib/couchbase/collection.rb', line 190

def exists(id, options = Options::Exists.new)
  resp = @backend.document_exists(bucket_name, "#{@scope_name}.#{@name}", id, options.to_backend)
  ExistsResult.new do |res|
    res.status = resp[:status]
    res.partition_id = resp[:partition_id]
    res.cas = resp[:cas] if res.status != :not_found
  end
end

#get(id, options = Options::Get.new) ⇒ GetResult

Fetches the full document from the collection

Examples:

Get document contents

res = collection.get("customer123")
res.content["addresses"]

# {"billing"=>
#   {"line1"=>"123 Any Street", "line2"=>"Anytown", "country"=>"United Kingdom"},
#  "delivery"=>
#   {"line1"=>"123 Any Street", "line2"=>"Anytown", "country"=>"United Kingdom"}}

Get partial document using projections

res = collection.get("customer123", Options::Get(projections: ["name", "addresses.billing"]))
res.content

# {"addresses"=>
#    {"billing"=>
#      {"country"=>"United Kingdom",
#       "line1"=>"123 Any Street",
#       "line2"=>"Anytown"}},
#   "name"=>"Douglas Reynholm"}

Parameters:

  • id (String)

    the document id which is used to uniquely identify it

  • options (Options::Get) (defaults to: Options::Get.new)

    request customization

Returns:



71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/couchbase/collection.rb', line 71

def get(id, options = Options::Get.new)
  resp = if options.need_projected_get?
           @backend.document_get_projected(bucket_name, "#{@scope_name}.#{@name}", id, options.to_backend)
         else
           @backend.document_get(bucket_name, "#{@scope_name}.#{@name}", id, options.to_backend)
         end
  GetResult.new do |res|
    res.transcoder = options.transcoder
    res.cas = resp[:cas]
    res.flags = resp[:flags]
    res.encoded = resp[:content]
    res.expiry = resp[:expiry] if resp.key?(:expiry)
  end
end

#get_all_replicas(id, options = Options::GetAllReplicas.new) ⇒ Array<GetReplicaResult>

Reads from all available replicas and the active node and returns the results

Parameters:

  • id (String)

    the document id which is used to uniquely identify it.

  • options (Options::GetAllReplicas) (defaults to: Options::GetAllReplicas.new)

    request customization

Returns:



170
# File 'lib/couchbase/collection.rb', line 170

def get_all_replicas(id, options = Options::GetAllReplicas.new) end

#get_and_lock(id, lock_time, options = Options::GetAndLock.new) ⇒ GetResult

Fetches the full document and write-locks it for the given duration

Examples:

Retrieve document and lock for 10 seconds

collection.get_and_lock("customer123", 10, Options::GetAndLock(timeout: 3_000))

Update document pessimistically

res = collection.get_and_lock("customer123", 10)
user_data = res.content
user_data["admin"] = true
collection.replace("user", user_data, Options::Upsert(cas: res.cas))

Parameters:

  • id (String)

    the document id which is used to uniquely identify it.

  • lock_time (Integer, #in_seconds)

    how long to lock the document (values over 30 seconds will be capped)

  • options (Options::GetAndLock) (defaults to: Options::GetAndLock.new)

    request customization

Returns:



130
131
132
133
134
135
136
137
138
139
140
# File 'lib/couchbase/collection.rb', line 130

def get_and_lock(id, lock_time, options = Options::GetAndLock.new)
  resp = @backend.document_get_and_lock(bucket_name, "#{@scope_name}.#{@name}", id,
                                        lock_time.respond_to?(:in_seconds) ? lock_time.public_send(:in_seconds) : lock_time,
                                        options.to_backend)
  GetResult.new do |res|
    res.transcoder = options.transcoder
    res.cas = resp[:cas]
    res.flags = resp[:flags]
    res.encoded = resp[:content]
  end
end

#get_and_touch(id, expiry, options = Options::GetAndTouch.new) ⇒ GetResult

Fetches a full document and resets its expiration time to the duration provided

Examples:

Retrieve document and prolong its expiration for another 10 seconds

collection.get_and_touch("customer123", 10)

Parameters:

  • id (String)

    the document id which is used to uniquely identify it.

  • expiry (Integer, #in_seconds)

    the new expiration time for the document

  • options (Options::GetAndTouch) (defaults to: Options::GetAndTouch.new)

    request customization

Returns:



152
153
154
155
156
157
158
159
160
161
162
# File 'lib/couchbase/collection.rb', line 152

def get_and_touch(id, expiry, options = Options::GetAndTouch.new)
  resp = @backend.document_get_and_touch(bucket_name, "#{@scope_name}.#{@name}", id,
                                         expiry.respond_to?(:in_seconds) ? expiry.public_send(:in_seconds) : expiry,
                                         options.to_backend)
  GetResult.new do |res|
    res.transcoder = options.transcoder
    res.cas = resp[:cas]
    res.flags = resp[:flags]
    res.encoded = resp[:content]
  end
end

#get_any_replica(id, options = Options::GetAnyReplica.new) ⇒ GetReplicaResult

Reads all available replicas, and returns the first found

Parameters:

  • id (String)

    the document id which is used to uniquely identify it.

  • options (Options::GetAnyReplica) (defaults to: Options::GetAnyReplica.new)

    request customization

Returns:



178
# File 'lib/couchbase/collection.rb', line 178

def get_any_replica(id, options = Options::GetAnyReplica.new) end

#get_multi(ids, options = Options::GetMulti.new) ⇒ Array<GetResult>

Note:

that it will not generate Error::DocumentNotFound exceptions in this case. The caller should check Couchbase::Collection::GetResult#error property of the result

Fetches multiple documents from the collection.

Examples:

Fetch “foo” and “bar” in a batch

res = collection.get(["foo", "bar"], Options::GetMulti(timeout: 3_000))
res[0].content #=> content of "foo"
res[1].content #=> content of "bar"

Parameters:

  • ids (Array<String>)

    the array of document identifiers

  • options (Options::GetMulti) (defaults to: Options::GetMulti.new)

    request customization

Returns:



100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/couchbase/collection.rb', line 100

def get_multi(ids, options = Options::GetMulti.new)
  collection_spec = "#{@scope_name}.#{@name}"
  resp = @backend.document_get_multi(ids.map { |id| [bucket_name, collection_spec, id] }, options.to_backend)
  resp.map do |entry|
    GetResult.new do |res|
      res.transcoder = options.transcoder
      res.cas = entry[:cas]
      res.flags = entry[:flags]
      res.encoded = entry[:content]
      res.error = entry[:error]
    end
  end
end

#insert(id, content, options = Options::Insert.new) ⇒ MutationResult

Inserts a full document which does not exist yet

Examples:

Insert new document in collection

res = collection.insert("mydoc", {"foo" => 42}, Options::Insert(expiry: 20))
res.cas #=> 242287264414742

Handle error when the document already exists

collection.exists("mydoc").exists? #=> true
begin
  res = collection.insert("mydoc", {"foo" => 42})
rescue Error::DocumentExists
  puts "Failed to insert the document, it already exists in the collection"
end

Parameters:

  • id (String)

    the document id which is used to uniquely identify it.

  • content (Object)

    the document content to insert

  • options (Options::Insert) (defaults to: Options::Insert.new)

    request customization

Returns:



284
285
286
287
288
289
290
291
# File 'lib/couchbase/collection.rb', line 284

def insert(id, content, options = Options::Insert.new)
  blob, flags = options.transcoder ? options.transcoder.encode(content) : [content, 0]
  resp = @backend.document_insert(bucket_name, "#{@scope_name}.#{@name}", id, blob, flags, options.to_backend)
  MutationResult.new do |res|
    res.cas = resp[:cas]
    res.mutation_token = extract_mutation_token(resp)
  end
end

#lookup_in(id, specs, options = Options::LookupIn.new) ⇒ LookupInResult

Performs lookups to document fragments

Examples:

Get list of IDs of completed purchases

lookup_specs = [
  LookupInSpec::get("purchases.complete")
]
collection.lookup_in("customer123", lookup_specs)

Parameters:

  • id (String)

    the document id which is used to uniquely identify it.

  • specs (Array<LookupInSpec>)

    the list of specifications which describe the types of the lookups to perform

  • options (Options::LookupIn) (defaults to: Options::LookupIn.new)

    request customization

Returns:



415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/couchbase/collection.rb', line 415

def lookup_in(id, specs, options = Options::LookupIn.new)
  resp = @backend.document_lookup_in(
    bucket_name, "#{@scope_name}.#{@name}", id,
    specs.map do |s|
      {
        opcode: s.type,
        xattr: s.xattr?,
        path: s.path,
      }
    end, options.to_backend
  )
  LookupInResult.new do |res|
    res.transcoder = options.transcoder
    res.cas = resp[:cas]
    res.deleted = resp[:deleted]
    res.encoded = resp[:fields].map do |field|
      SubDocumentField.new do |f|
        f.exists = field[:exists]
        f.index = field[:index]
        f.path = field[:path]
        f.status = field[:status]
        f.error = field[:error]
        f.value = field[:value]
        f.type = field[:type]
      end
    end
  end
end

#mutate_in(id, specs, options = Options::MutateIn.new) ⇒ MutateInResult

Performs mutations to document fragments

Examples:

Append number into subarray of the document

mutation_specs = [
  MutateInSpec::array_append("purchases.complete", [42])
]
collection.mutate_in("customer123", mutation_specs, Options::MutateIn(expiry: 10))

Parameters:

  • id (String)

    the document id which is used to uniquely identify it.

  • specs (Array<MutateInSpec>)

    the list of specifications which describe the types of the lookups to perform

  • options (Options::MutateIn) (defaults to: Options::MutateIn.new)

    request customization

Returns:



457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
# File 'lib/couchbase/collection.rb', line 457

def mutate_in(id, specs, options = Options::MutateIn.new)
  resp = @backend.document_mutate_in(
    bucket_name, "#{@scope_name}.#{@name}", id,
    specs.map do |s|
      {
        opcode: s.type,
        path: s.path,
        param: s.param,
        xattr: s.xattr?,
        expand_macros: s.expand_macros?,
        create_path: s.create_path?,
      }
    end, options.to_backend
  )
  result = MutateInResult.new do |res|
    res.transcoder = options.transcoder
    res.cas = resp[:cas]
    res.deleted = resp[:deleted]
    res.mutation_token = extract_mutation_token(resp)
    res.first_error_index = resp[:first_error_index]
    res.encoded = resp[:fields].map do |field|
      SubDocumentField.new do |f|
        f.exists = field[:exists]
        f.path = field[:path]
        f.status = field[:status]
        f.error = field[:error]
        f.value = field[:value]
        f.type = field[:type]
      end
    end
  end
  raise result.first_error unless result.success?

  result
end

#remove(id, options = Options::Remove.new) ⇒ MutationResult

Removes a document from the collection

Examples:

Remove the document in collection

res = collection.remove("customer123")
res.cas #=> 241994216651798

Remove the document in collection, but apply optimistic lock

res = collection.upsert("mydoc", {"foo" => 42})
res.cas #=> 7751414725654

begin
  res = collection.remove("mydoc", Options::Remove(cas: 3735928559))
rescue Error::CasMismatch
  puts "Failed to remove the document, it might be changed by other application"
end

Parameters:

  • id (String)

    the document id which is used to uniquely identify it.

  • options (Options::Remove) (defaults to: Options::Remove.new)

    request customization

Returns:



219
220
221
222
223
224
225
# File 'lib/couchbase/collection.rb', line 219

def remove(id, options = Options::Remove.new)
  resp = @backend.document_remove(bucket_name, "#{@scope_name}.#{@name}", id, options.to_backend)
  MutationResult.new do |res|
    res.cas = resp[:cas]
    res.mutation_token = extract_mutation_token(resp)
  end
end

#remove_multi(ids, options = Options::RemoveMulti.new) ⇒ Array<MutationResult>

Note:

that it will not generate Error::DocumentNotFound or Error::CasMismatch exceptions in this case. The caller should check Couchbase::Collection::MutationResult#error property of the result

Removes a list of the documents from the collection

Examples:

Remove two documents in collection. For “mydoc” apply optimistic lock

res = collection.upsert("mydoc", {"foo" => 42})
res.cas #=> 7751414725654

res = collection.remove_multi(["foo", ["mydoc", res.cas]])
if res[1].error.is_a?(Error::CasMismatch)
  puts "Failed to remove the document, it might be changed by other application"
end

Parameters:

  • ids (Array<String, Array>)

    the array of document ids, or ID/CAS pairs [String,Integer]

  • options (Options::RemoveMulti) (defaults to: Options::RemoveMulti.new)

    request customization

Returns:



245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/couchbase/collection.rb', line 245

def remove_multi(ids, options = Options::RemoveMulti.new)
  collection_spec = "#{@scope_name}.#{@name}"
  resp = @backend.document_remove_multi(ids.map do |id|
    case id
    when String
      [bucket_name, collection_spec, id, nil]
    when Array
      [bucket_name, collection_spec, id[0], id[1]]
    else
      raise ArgumentError, "id argument of remove_multi must be a String or Array<String, Integer>, given: #{id.inspect}"
    end
  end, options.to_backend)
  resp.map do |entry|
    MutationResult.new do |res|
      res.cas = entry[:cas]
      res.mutation_token = extract_mutation_token(entry)
    end
  end
end

#replace(id, content, options = Options::Replace.new) ⇒ MutationResult

Replaces a full document which already exists

Examples:

Replace new document in collection with optimistic locking

res = collection.get("mydoc")
res = collection.replace("mydoc", {"foo" => 42}, Options::Replace(cas: res.cas))
res.cas #=> 242287264414742

Parameters:

  • id (String)

    the document id which is used to uniquely identify it.

  • content (Object)

    the document content to upsert

  • options (Options::Replace) (defaults to: Options::Replace.new)

    request customization

Returns:



357
358
359
360
361
362
363
364
# File 'lib/couchbase/collection.rb', line 357

def replace(id, content, options = Options::Replace.new)
  blob, flags = options.transcoder ? options.transcoder.encode(content) : [content, 0]
  resp = @backend.document_replace(bucket_name, "#{@scope_name}.#{@name}", id, blob, flags, options.to_backend)
  MutationResult.new do |res|
    res.cas = resp[:cas]
    res.mutation_token = extract_mutation_token(resp)
  end
end

#touch(id, expiry, options = Options::Touch.new) ⇒ MutationResult

Update the expiration of the document with the given id

Examples:

Reset expiration timer for document to 30 seconds

res = collection.touch("customer123", 30)

Parameters:

  • id (String)

    the document id which is used to uniquely identify it.

  • expiry (Integer, #in_seconds)

    new expiration time for the document

  • options (Options::Touch) (defaults to: Options::Touch.new)

    request customization

Returns:



376
377
378
379
380
381
382
383
# File 'lib/couchbase/collection.rb', line 376

def touch(id, expiry, options = Options::Touch.new)
  resp = @backend.document_touch(bucket_name, "#{@scope_name}.#{@name}", id,
                                 expiry.respond_to?(:in_seconds) ? expiry.public_send(:in_seconds) : expiry,
                                 options.to_backend)
  MutationResult.new do |res|
    res.cas = resp[:cas]
  end
end

#unlock(id, cas, options = Options::Unlock.new) ⇒ void

This method returns an undefined value.

Unlocks a document if it has been locked previously

Examples:

Lock (pessimistically) and unlock document

res = collection.get_and_lock("customer123", 10)
collection.unlock("customer123", res.cas)

Parameters:

  • id (String)

    the document id which is used to uniquely identify it.

  • cas (Integer)

    CAS value which is needed to unlock the document

  • options (Options::Unlock) (defaults to: Options::Unlock.new)

    request customization

Raises:



398
399
400
# File 'lib/couchbase/collection.rb', line 398

def unlock(id, cas, options = Options::Unlock.new)
  @backend.document_unlock(bucket_name, "#{@scope_name}.#{@name}", id, cas, options.to_backend)
end

#upsert(id, content, options = Options::Upsert.new) ⇒ MutationResult

Upserts (inserts or updates) a full document which might or might not exist yet

Examples:

Upsert new document in collection

res = collection.upsert("mydoc", {"foo" => 42}, Options::Upsert(expiry: 20))
res.cas #=> 242287264414742

Parameters:

  • id (String)

    the document id which is used to uniquely identify it.

  • content (Object)

    the document content to upsert

  • options (Options::Upsert) (defaults to: Options::Upsert.new)

    request customization

Returns:



304
305
306
307
308
309
310
311
# File 'lib/couchbase/collection.rb', line 304

def upsert(id, content, options = Options::Upsert.new)
  blob, flags = options.transcoder ? options.transcoder.encode(content) : [content, 0]
  resp = @backend.document_upsert(bucket_name, "#{@scope_name}.#{@name}", id, blob, flags, options.to_backend)
  MutationResult.new do |res|
    res.cas = resp[:cas]
    res.mutation_token = extract_mutation_token(resp)
  end
end

#upsert_multi(id_content, options = Options::UpsertMulti.new) ⇒ Array<MutationResult>

Note:

that it will not generate exceptions in this case. The caller should check Couchbase::Collection::MutationResult#error property of the result

Upserts (inserts or updates) a list of documents which might or might not exist yet

Examples:

Upsert two documents with IDs “foo” and “bar” into a collection

res = collection.upsert_multi([
  "foo", {"foo" => 42},
  "bar", {"bar" => "some value"}
])
res[0].cas #=> 7751414725654
res[1].cas #=> 7751418925851

Parameters:

  • id_content (Array<Array>)

    array of tuples String,Object, where first entry treated as document key, and the second as value to upsert.

  • options (Options::UpsertMulti) (defaults to: Options::UpsertMulti.new)

    request customization

Returns:



331
332
333
334
335
336
337
338
339
340
341
342
343
# File 'lib/couchbase/collection.rb', line 331

def upsert_multi(id_content, options = Options::UpsertMulti.new)
  collection_spec = "#{@scope_name}.#{@name}"
  resp = @backend.document_upsert_multi(id_content.map do |(id, content)|
    blob, flags = options.transcoder ? options.transcoder.encode(content) : [content, 0]
    [bucket_name, collection_spec, id, blob, flags]
  end, options.to_backend)
  resp.map do |entry|
    MutationResult.new do |res|
      res.cas = entry[:cas]
      res.mutation_token = extract_mutation_token(entry)
    end
  end
end