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_doc
Com 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 |
função Sobre a atualização(doc, meta) { registro('input doc ', doc); registro('input meta', meta); // pode ser o mesmo ou diferente var new_meta = {"id":"test_adv_get::1"}; var resultado = couchbase.obter(src_bkt,new_meta); se (resultado.sucesso) { registro('success adv. get: result',resultado); } mais { registro('failure adv. get: id',new_meta.id,'resultado',resultado); } } |
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, "tipo": "test_adv_get" }, "meta": { "id": "test_adv_get::1", "cas": "1610034762747412480", "data_type": "json" }, "sucesso": verdadeiro } { "doc": { "a": 1, "aleatório": 0.09799092443129842 }, "meta": { "id": "test_adv_insert:1", "cas": "1610140272584884224", "expiry_date" (data de expiração): "2021-01-08T21:12:12.000Z", "data_type": "json" }, "sucesso": verdadeiro } { "error" (erro): { "código": 272, "name" (nome): "LCB_KEY_ENOENT", "desc": "A chave do documento não existe no servidor", "key_not_found": verdadeiro }, "sucesso": falso } |
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 |
função Sobre a atualização(doc, meta) { registro('input meta', meta); registro('input doc ', doc); // pode ser o mesmo ou diferente var new_meta = {"id":"test_adv_insert:1"}; // opcional definir uma expiração de 60 segundos no futuro // new_meta.expiry_date = new Date(Date.now() + 60 * 1000); var novo_doc = doc; novo_doc.aleatório = Matemática.aleatório(); var resultado = couchbase.inserir(src_bkt,new_meta,novo_doc); se (resultado.sucesso) { registro('success adv. insert: result',resultado); } mais { registro('failure adv. insert: id',new_meta.id,'resultado',resultado); } } |
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" }, "sucesso": verdadeiro } { "error" (erro): { "código": 272, "name" (nome): "LCB_KEY_EEXISTS", "desc": "A chave do documento já existe no servidor.", "key_already_exists": verdadeiro }, "sucesso": falso } |
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 |
função Sobre a atualização(doc, meta) { registro('input meta', meta); registro('input doc ', doc); // pode ser o mesmo ou diferente var new_meta = {"id":"test_adv_upsert:1"}; // CAS, se fornecido, será ignorado // opcional definir uma expiração de 60 segundos no futuro // new_meta.expiry_date = new Date(Date.now() + 60 * 1000); var novo_doc = doc; novo_doc.aleatório = Matemática.aleatório(); var resultado = couchbase.upsert(src_bkt,new_meta,novo_doc); se (resultado.sucesso) { registro('success adv. upsert: result',resultado); } mais { registro('failure adv. upsert: id',new_meta.id,'resultado',resultado); } } |
Um exemplo de valor de retorno:
1 2 3 4 5 6 7 |
{ "meta": { "id": "test_adv_upsert:1", "cas": "1610127444908376064" }, "sucesso": verdadeiro } |
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 |
função Sobre a atualização(doc, meta) { registro('input meta', meta); registro('input doc ', doc); var modo = 3; // 1-> sem CA, 2-> incompatibilidade na CA, 3-> bom CAS // Configuração, certifique-se de que temos nosso documento para "substituir", ignore quaisquer erros couchbase.inserir(src_bkt,{"id":"test_adv_replace:10"},{"a:": 1}); var new_meta; se (modo === 1) { // Se não passarmos nenhum CAS, ele será bem-sucedido new_meta = {"id":"test_adv_replace:10"}; // opcional definir uma expiração de 60 segundos no futuro // new_meta.expiry_date = new Date(Date.now() + 60 * 1000); } se (modo === 2) { // Se passarmos um CAS não correspondente, ele falhará, portanto, teste isso new_meta = {"id":"test_adv_replace:10", "cas":"1111111111111111111"}; } se (modo === 3) { // Se passarmos o CAS correspondente ou atual, ele será bem-sucedido var tmp_r = couchbase.obter(src_bkt,{"id":"test_adv_replace:10"}); se (tmp_r.sucesso) { // Aqui usamos o CAS atual que acabou de ser lido via couchbase.get(...) new_meta = {"id":"test_adv_replace:10", "cas": tmp_r.meta.cas}; } mais { registro('Cannot replace non-existing key that create it and rerun',"test_adv_replace:10"); retorno; } } var novo_doc = doc; novo_doc.aleatório = Matemática.aleatório(); var resultado = couchbase.substituir(src_bkt,new_meta,novo_doc); se (resultado.sucesso) { registro('success adv. replace: result',resultado); } mais { registro('failure adv. replace: id',new_meta.id,'resultado',resultado); } } |
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" }, "sucesso": verdadeiro } { "error" (erro): { "código": 272, "name" (nome): "LCB_KEY_EEXISTS", "desc": "A chave do documento existe com um valor CAS diferente do especificado", "cas_mismatch": verdadeiro }, "sucesso": falso } |
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 |
função Sobre a atualização(doc, meta) { registro('input meta', meta); registro('input doc ', doc); var modo = 4; // 1-> nenhuma CA, 2-> incompatibilidade na CA, 3-> bom CAS, 4-> essa chave não existe // Configuração, certifique-se de que temos nosso documento para "excluir", ignore quaisquer erros couchbase.inserir(src_bkt,{"id":"test_adv_delete:10"},{"a:": 1}); var new_meta; se (modo === 1) { // Se não passarmos nenhum CAS, ele será bem-sucedido new_meta = {"id":"test_adv_delete:10"}; // opcional definir uma expiração de 60 segundos no futuro // new_meta.expiry_date = new Date(Date.now() + 60 * 1000); } se (modo === 2) { // Se passarmos um CAS não correspondente, ele falhará, portanto, teste isso new_meta = {"id":"test_adv_delete:10", "cas":"1111111111111111111"}; } se (modo === 3) { // Se passarmos o CAS correspondente ou atual, ele será bem-sucedido var tmp_r = couchbase.obter(src_bkt,{"id":"test_adv_delete:10"}); se (tmp_r.sucesso) { // Aqui usamos o CAS atual que acabou de ser lido via couchbase.get(...) new_meta = {"id":"test_adv_delete:10", "cas": tmp_r.meta.cas}; } mais { registro('Cannot delete non-existing key that create it and rerun',"test_adv_delete:10"); retorno; } } se (modo === 4) { // Remover para que tenhamos: não existe tal chave excluir src_bkt["test_adv_delete:10"] new_meta = {"id":"test_adv_delete:10"}; } var resultado = couchbase.excluir(src_bkt,new_meta); se (resultado.sucesso) { registro('success adv. delete: result',resultado); } mais { registro('failure adv. delete: id',new_meta.id,'resultado',resultado); } } |
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" }, "sucesso": verdadeiro } { "error" (erro): { "código": 272, "name" (nome): "LCB_KEY_EEXISTS", "desc": "A chave do documento existe com um valor CAS diferente do especificado", "cas_mismatch": verdadeiro }, "sucesso": falso } { "error" (erro): { "código": 272, "name" (nome): "LCB_KEY_ENOENT", "desc": "A chave do documento não existe no servidor", "key_not_found": verdadeiro }, "sucesso": falso } |
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" (contagem): 23} // 23 é o valor atual do contador |
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 |
função Sobre a atualização(doc, meta) { registro('input meta', meta); registro('input doc ', doc); // se doc.count não existir, ele será criado var ctr_meta = {"id": "my_atomic_counter:1" }; var resultado = couchbase.incremento(src_bkt,ctr_meta); se (resultado.sucesso) { registro('success adv. increment: result',resultado); } mais { registro('failure adv. increment: id',ctr_meta.id,'resultado',resultado); } } |
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" (contagem): 24 }, "meta": { "id": "key::1", "cas": "1609374571840471040" }, "sucesso": verdadeiro } |
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" (contagem): 23} // 23 é o valor atual do contador |
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 |
função Sobre a atualização(doc, meta) { registro('input meta', meta); registro('input doc ', doc); // se doc.count não existir, ele será criado var ctr_meta = {"id": "my_atomic_counter:1" }; var resultado = couchbase.decréscimo(src_bkt,ctr_meta); se (resultado.sucesso) { registro('success adv. decrement: result',resultado); } mais { registro('failure adv. decrement: id',ctr_meta.id,'resultado',resultado); } } |
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" (contagem): 22 }, "meta": { "id": "key::1", "cas": "1609374770297176064" }, "sucesso": verdadeiro } |
Referências