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
more...

Overview

Provides access to all collection APIs

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

[View source]

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

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.


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

def bucket_name
  @bucket_name
end

#nameObject (readonly)

Returns the value of attribute name.


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

def name
  @name
end

#scope_nameObject (readonly)

Returns the value of attribute scope_name.


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

def scope_name
  @scope_name
end

Instance Method Details

#binaryBinaryCollection

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

Returns:

[View source]

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

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:

[View source]

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

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:

[View source]

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

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:

[View source]

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

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:

[View source]

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

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, Time)

    the new expiration time for the document

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

    request customization

Returns:

[View source]

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

def get_and_touch(id, expiry, options = Options::GetAndTouch.new)
  resp = @backend.document_get_and_touch(bucket_name, "#{@scope_name}.#{@name}", id,
                                         Utils::Time.extract_expiry_time(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:

[View source]

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

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:

[View source]

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

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:

[View source]

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

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)

Retrieve country name and check if pending purchases array is empty

collection.lookup_in "customer123", [
  LookupInSpec.get("addresses.delivery.country"),
  LookupInSpec.exists("purchases.pending[-1]"),
]

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:

[View source]

423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
# File 'lib/couchbase/collection.rb', line 423

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))

Write meta attribute, remove array entry and replace email field

collection.mutate_in("customer123", [
  MutateInSpec.upsert("_framework.model_type", "Customer").xattr,
  MutateInSpec.remove("addresses.billing[2]"),
  MutateInSpec.replace("email", "dougr96@hotmail.com"),
])

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:

[View source]

472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
# File 'lib/couchbase/collection.rb', line 472

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:

[View source]

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

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:

[View source]

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

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)
      res.error = entry[:error]
    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:

[View source]

360
361
362
363
364
365
366
367
# File 'lib/couchbase/collection.rb', line 360

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, Time)

    new expiration time for the document

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

    request customization

Returns:

[View source]

379
380
381
382
383
384
385
386
# File 'lib/couchbase/collection.rb', line 379

def touch(id, expiry, options = Options::Touch.new)
  resp = @backend.document_touch(bucket_name, "#{@scope_name}.#{@name}", id,
                                 Utils::Time.extract_expiry_time(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:

[View source]

401
402
403
# File 'lib/couchbase/collection.rb', line 401

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:

[View source]

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

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:

[View source]

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

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)
      res.error = entry[:error]
    end
  end
end