Os Advanced Bucket Accessors no Couchbase possibilitam o acesso à funcionalidade avançada do armazenamento de valores-chave (KV) usando os seguintes operadores internos.
Eles utilizam os mesmos vínculos de bucket definidos no manipulador como Basic Bucket Accessors, mas expõem um conjunto mais rico de opções e operadores que podem ser usados para:
- Definir ou recuperar expirações
- Resolver condições de corrida por meio do CAS
- Manipular itens de KV quentes sob alta contenção
Observe que Acessores básicos de bucket são muito mais fáceis de usar, têm uma API trivial e também são um pouco mais rápidos do que os correspondentes Advanced Bucket Accessors.
No Couchbase Server 6.6.1, foram adicionados os seguintes acessores avançados de bucket:
Esses sete novos Bucket Accessors permitem utilizar e aproveitar o CAS diretamente para lidar com a contenção e/ou definir a expiração de um documento (ou TTL) no serviço de dados (ou KV) via Eventos além de realizar operações de contador atômico distribuído.
Por exemplo, em vez de confiar cegamente nos Basic Bucket Accessors para uma operação do tipo upsert src_bkt[id_str] = algum_docCom os Advanced Accessors, você pode resolver a contenção (ou possível contenção) em chaves que têm mutações simultâneas de diferentes origens com lógica orientada por JavaScript em sua Eventing Function.
-
- Se o documento não existir, você poderá usar
couchbase.insert(src_bkt, {"id: id_str}, some_doc)e verificar se o valor de retorno é bem-sucedido - Se o documento existir, você poderá usar
couchbase.replace(src_bkt, {"id: id_str, "cas": current_cas}, some_doc)e verificar se o valor de retorno é bem-sucedido ou se há uma incompatibilidade de CAS.
- Se o documento não existir, você poderá usar
Para ver exemplos completos, incluindo JavaScript, mutações de entrada, mutações de saída e/ou mensagens de registro para cada Advanced Bucket Accessor, consulte Scriptlets: Manipuladores de acessores avançados na seção de exemplos da documentação.
GET avançado: resultado = couchbase.get(binding, meta)
Essa operação permite ler um documento junto com metadados do bucket e operações subsequentes para utilizar o CAS ou verificar/modificar o data de expiração.
Compare isso com o Basic Bucket Accessor OBTER que simplesmente expõe uma ligação ou um mapa JavaScript, var adoc = src_bkt[meta.id]onde o valor de retorno é apenas o documento sem nenhum metadado.
Abaixo está um exemplo do Advanced OBTER operação.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
function OnUpdate(doc, meta) { log('input doc ', doc); log('input meta', meta); // could be the same or different var new_meta = {"id":"test_adv_get::1"}; var result = couchbase.get(src_bkt,new_meta); if (result.success) { log('success adv. get: result',result); } else { log('failure adv. get: id',new_meta.id,'result',result); } } |
Alguns exemplos de valores de retorno:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
{ "doc": { "id": 1, "type": "test_adv_get" }, "meta": { "id": "test_adv_get::1", "cas": "1610034762747412480", "data_type": "json" }, "success": true } { "doc": { "a": 1, "random": 0.09799092443129842 }, "meta": { "id": "test_adv_insert:1", "cas": "1610140272584884224", "expiry_date": "2021-01-08T21:12:12.000Z", "data_type": "json" }, "success": true } { "error": { "code": 272, "name": "LCB_KEY_ENOENT", "desc": "The document key does not exist on the server", "key_not_found": true }, "success": false } |
INSERÇÃO avançada: resultado = couchbase.insert(binding, meta, doc)
Essa operação permite criar um novo documento no bucket. Essa operação falhará se o documento com a chave especificada já existir. Permite especificar um tempo de expiração (ou TTL) a ser definido no documento.
Não há nenhuma operação do Basic Bucket Accessor análoga à do Advanced INSERIR operação (como src_bkt[meta.id] = adoc é mais como um upsert).
Abaixo está um exemplo do Advanced INSERIR operação.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function OnUpdate(doc, meta) { log('input meta', meta); log('input doc ', doc); // could be the same or different var new_meta = {"id":"test_adv_insert:1"}; // optional set an expiry 60 seconds in the future // new_meta.expiry_date = new Date(Date.now() + 60 * 1000); var new_doc = doc; new_doc.random = Math.random(); var result = couchbase.insert(src_bkt,new_meta,new_doc); if (result.success) { log('success adv. insert: result',result); } else { log('failure adv. insert: id',new_meta.id,'result',result); } } |
Alguns exemplos de valores de retorno:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "meta": { "id": "test_adv_insert:1", "cas": "1610041053310025728" }, "success": true } { "error": { "code": 272, "name": "LCB_KEY_EEXISTS", "desc": "The document key already exists in the server.", "key_already_exists": true }, "success": false } |
UPSERT avançado: resultado = couchbase.upsert(binding, meta, doc)
Essa operação permite atualizar um documento existente no bucket ou, se não houver, criar um novo documento com a chave especificada. A operação não permite especificar o CAS (ele será silenciosamente ignorado). Ela também permite especificar um tempo de expiração (ou TTL) a ser definido no documento.
Compare isso com o Basic Bucket Accessor CONJUNTO que simplesmente usa um mapa JavaScript exposto definido por meio de um alias de vinculação de bucket src_bkt[meta.id] = adoc. Para o básico CONJUNTO não há valor de retorno (sem status e sem metadados) e, portanto, não há como verificar o valor do CAS.
Abaixo está um exemplo do Advanced UPSERT operação.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function OnUpdate(doc, meta) { log('input meta', meta); log('input doc ', doc); // could be the same or different var new_meta = {"id":"test_adv_upsert:1"}; // CAS if supplied will be ignored // optional set an expiry 60 seconds in the future // new_meta.expiry_date = new Date(Date.now() + 60 * 1000); var new_doc = doc; new_doc.random = Math.random(); var result = couchbase.upsert(src_bkt,new_meta,new_doc); if (result.success) { log('success adv. upsert: result',result); } else { log('failure adv. upsert: id',new_meta.id,'result',result); } } |
Um exemplo de valor de retorno:
|
1 2 3 4 5 6 7 |
{ "meta": { "id": "test_adv_upsert:1", "cas": "1610127444908376064" }, "success": true } |
REPLACE avançado: resultado = couchbase.replace(binding, meta, doc)
Esta operação substitui um documento existente no bucket. Essa operação falhará se o documento com a chave especificada não existir. Essa operação permite especificar um valor CAS que deve ser correspondido como uma pré-condição antes de prosseguir com a operação. Ela também permite especificar um tempo de expiração (ou TTL) a ser definido no documento.
Não há nenhuma operação do Basic Bucket Accessor análoga à do Advanced SUBSTITUIR operação (como src_bkt[meta.id] = adoc é mais como um upsert).
Abaixo está um exemplo do Advanced SUBSTITUIR operação.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
function OnUpdate(doc, meta) { log('input meta', meta); log('input doc ', doc); var mode = 3; // 1-> no CA, 2-> mismatch in CA, 3-> good CAS // Setup, make sure we have our doc to "replace", ignore any errors couchbase.insert(src_bkt,{"id":"test_adv_replace:10"},{"a:": 1}); var new_meta; if (mode === 1) { // If we pass no CAS it will succeed new_meta = {"id":"test_adv_replace:10"}; // optional set an expiry 60 seconds in the future // new_meta.expiry_date = new Date(Date.now() + 60 * 1000); } if (mode === 2) { // If we pass a non-matching CAS it will fail, so test this new_meta = {"id":"test_adv_replace:10", "cas":"1111111111111111111"}; } if (mode === 3) { // If we pass the matching or current CAS it will succeed var tmp_r = couchbase.get(src_bkt,{"id":"test_adv_replace:10"}); if (tmp_r.success) { // Here we use the current CAS just read via couchbase.get(...) new_meta = {"id":"test_adv_replace:10", "cas": tmp_r.meta.cas}; } else { log('Cannot replace non-existing key that create it and rerun',"test_adv_replace:10"); return; } } var new_doc = doc; new_doc.random = Math.random(); var result = couchbase.replace(src_bkt,new_meta,new_doc); if (result.success) { log('success adv. replace: result',result); } else { log('failure adv. replace: id',new_meta.id,'result',result); } } |
Alguns exemplos de valores de retorno:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "meta": { "id": "test_adv_replace:10", "cas": "1610130177286144000" }, "success": true } { "error": { "code": 272, "name": "LCB_KEY_EEXISTS", "desc": "The document key exists with a CAS value different than specified", "cas_mismatch": true }, "success": false } |
DELETE avançado: resultado = couchbase.delete(binding, meta)
Essa operação permite excluir um documento no compartimento especificado pela chave. Opcionalmente, pode ser especificado um valor CAS que será correspondido como uma pré-condição para prosseguir com a operação.
Compare isso com o Basic Bucket Accessor DEL que simplesmente usa uma ligação ou um mapa JavaScript exposto, excluir src_bkt[meta.id]onde não há valor de retorno (sem status e sem metadados).
Abaixo está um exemplo do Advanced DELETE operação.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
function OnUpdate(doc, meta) { log('input meta', meta); log('input doc ', doc); var mode = 4; // 1-> no CA, 2-> mismatch in CA, 3-> good CAS, 4-> no such key // Setup, make sure we have our doc to "delete", ignore any errors couchbase.insert(src_bkt,{"id":"test_adv_delete:10"},{"a:": 1}); var new_meta; if (mode === 1) { // If we pass no CAS it will succeed new_meta = {"id":"test_adv_delete:10"}; // optional set an expiry 60 seconds in the future // new_meta.expiry_date = new Date(Date.now() + 60 * 1000); } if (mode === 2) { // If we pass a non-matching CAS it will fail, so test this new_meta = {"id":"test_adv_delete:10", "cas":"1111111111111111111"}; } if (mode === 3) { // If we pass the matching or current CAS it will succeed var tmp_r = couchbase.get(src_bkt,{"id":"test_adv_delete:10"}); if (tmp_r.success) { // Here we use the current CAS just read via couchbase.get(...) new_meta = {"id":"test_adv_delete:10", "cas": tmp_r.meta.cas}; } else { log('Cannot delete non-existing key that create it and rerun',"test_adv_delete:10"); return; } } if (mode === 4) { // Remove so that we have: no such key delete src_bkt["test_adv_delete:10"] new_meta = {"id":"test_adv_delete:10"}; } var result = couchbase.delete(src_bkt,new_meta); if (result.success) { log('success adv. delete: result',result); } else { log('failure adv. delete: id',new_meta.id,'result',result); } } |
Alguns exemplos de valores de retorno:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
{ "meta": { "id": "key::10", "cas": "1609374065129816064" }, "success": true } { "error": { "code": 272, "name": "LCB_KEY_EEXISTS", "desc": "The document key exists with a CAS value different than specified", "cas_mismatch": true }, "success": false } { "error": { "code": 272, "name": "LCB_KEY_ENOENT", "desc": "The document key does not exist on the server", "key_not_found": true }, "success": false } |
INCREMENTO avançado: resultado = couchbase.increment(binding, meta)
Essa operação incrementa atomicamente o campo contagem no documento especificado. O documento deve ter a estrutura abaixo:
|
1 |
{"count": 23} // 23 is the current counter value |
O incremento retorna o valor pós-incremento.
Se o documento do contador especificado não existir, será criado um com contagem como 0 e a estrutura mencionada acima. Assim, o primeiro valor retornado será 1.
Devido a limitações na API do mecanismo KV, essa operação não pode manipular contadores de documentos completos no momento.
Não há nenhuma operação do Basic Bucket Accessor análoga à do Advanced INCREMENTO operação.
Abaixo está um exemplo do Advanced INCREMENTO operação.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function OnUpdate(doc, meta) { log('input meta', meta); log('input doc ', doc); // if doc.count doesn't exist it will be created var ctr_meta = {"id": "my_atomic_counter:1" }; var result = couchbase.increment(src_bkt,ctr_meta); if (result.success) { log('success adv. increment: result',result); } else { log('failure adv. increment: id',ctr_meta.id,'result',result); } } |
Um exemplo de valor de retorno, supondo que você crie este KEY "my_atomic_counter:1" DOC {"count": 23} Se a função Eventing acima for implementada, a contagem será imediatamente incrementada:
|
1 2 3 4 5 6 7 8 9 10 |
{ "doc": { "count": 24 }, "meta": { "id": "key::1", "cas": "1609374571840471040" }, "success": true } |
DECREMENTO avançado: resultado = couchbase.decrement(binding, meta)
Essa operação diminui atomicamente o campo contagem no documento especificado. O documento deve ter a estrutura abaixo:
|
1 |
{"count": 23} // 23 is the current counter value |
O decréscimo retorna o valor pós-decremento.
Se o documento do contador especificado não existir, será criado um com a função contagem como 0 e a estrutura mencionada acima. Como resultado, o primeiro valor retornado será -1.
Devido a limitações na API do mecanismo KV, essa operação não pode manipular contadores de documentos completos no momento.
Não há nenhuma operação do Basic Bucket Accessor análoga à do Advanced DECREMENTO operação.
Abaixo está um exemplo do Advanced DECREMENTO operação.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function OnUpdate(doc, meta) { log('input meta', meta); log('input doc ', doc); // if doc.count doesn't exist it will be created var ctr_meta = {"id": "my_atomic_counter:1" }; var result = couchbase.decrement(src_bkt,ctr_meta); if (result.success) { log('success adv. decrement: result',result); } else { log('failure adv. decrement: id',ctr_meta.id,'result',result); } } |
Um exemplo de valor de retorno, supondo que você crie este KEY "my_atomic_counter:1" DOC {"count": 23} Se a função Eventing acima for implementada, a contagem será imediatamente diminuída:
|
1 2 3 4 5 6 7 8 9 10 |
{ "doc": { "count": 22 }, "meta": { "id": "key::1", "cas": "1609374770297176064" }, "success": true } |
Referências