Como ficar mais enxuto com o SubDocument e o Java SDK

Nesta postagem do blog, apresentaremos um novo recurso interessante do próximo Versão do Couchbase Server 4.5 (codinome Watson), agora em Beta.

Estamos falando sobre o API de subdocumento (abreviado para subdoc).

Editar: Esta postagem do blog foi editada com atualizações do 4.5 Beta e do Java SDK 2.2.6.

Para conhecer outros recursos do Couchbase 4.5, consulte as postagens do blog de Don Pinto sobre o Visualização do desenvolvedor e o Beta.

Do que se trata?

O subdocumento é um recurso do lado do servidor que adiciona ao Memcached protocolo que alimenta o Couchbase Operações de chave-valor. Ele adiciona algumas operações que atuam em um único JSON mas, em vez de forçá-lo a recuperar o conteúdo completo do documento, ele permite que você especifique o caminho dentro do JSON que você está interessado em recuperar ou alterar.

Vou lhe mostrar por que isso é interessante com o seguinte cenário: digamos que você tenha um documento JSON grande (e eu quero dizer laaaaarge) armazenado sob o ID K no Couchbase. Dentro do documento, no dicionário submarino há um alguns que você deseja atualizar. Como você faria isso com o Couchbase 4.1?

É isso mesmo, você precisa executar um get(k) de todo o documento, modificar seu conteúdo localmente e, em seguida, executar um upsert (ou um substituir). Você não apenas transmite todo o documento grande pela rede quando está interessado apenas em uma pequena parte dele, mas também transmiti-lo duas vezes!

O subdoc A API permite operações mais simples nesses casos. Escolha a operação que deseja executar em seu documento e forneça a chave, o caminho dentro do JSON e, opcionalmente, o valor que deseja usar para essa operação, e voilà!

Em nosso exemplo anterior, o caminho seria "sub.value". Isso é bastante natural e consistente com a sintaxe de caminho usada em nossa linguagem de consulta, N1QL. Aqui está a aparência, não desenhada em escala :)

Na verdade, a mensagem tem apenas alguns bytes, portanto, quanto maior for o documento JSON original, maior será o benefício.

A API do cliente

Agora, aposto que tenho sua atenção. Mas quais são as operações oferecidas e como é a API?

Vamos usar o exemplo da API Java, conforme oferecido pelo 2.2.6 Java SDK.

Para cada exemplo, consideraremos que um "subdoc" O documento JSON existe no banco de dados e tem o seguinte conteúdo:

Também consideramos que a Balde instância, baldeestá disponível.

Operações de pesquisa

Sem falar em mutações dentro de um JSON, às vezes você só quer ler um único valor escondido no fundo do documento. Ou apenas deseja verificar se uma entrada está lá. O Subdoc oferece duas operações (obter e existe) para fazer exatamente isso, que são disponibilizados por meio do bucket.lookupIn(String key) método.

O lookupIn na verdade, fornece a você um construtor direcionado a um único documento JSON ("chave"), que, por sua vez, você pode usar para descrever com fluência as operações que deseja executar. Depois de ter todo o conjunto de especificações de pesquisa pronto, você pode executar a operação chamando a função executar() método. É claro que ele também pode ser usado para uma única pesquisa.

Esse método retorna um Fragmento de documento em Java, representando o resultado. Observe que as pesquisas múltiplas sempre retornam esse resultado, desde que não ocorra nenhum erro no nível do documento (ou seja, o documento não existe ou não é JSON).

Você pode obter o resultado individual de cada operação chamando result.content(String path) ou result.content(int operationIndex) (se você tiver várias operações direcionadas ao mesmo caminho, nesse caso, a primeira sempre retornará o resultado da primeira). Se houver um erro, você obterá a classe filha apropriada de SubDocumentException. Caso contrário, você obtém o valor (ou "true" no caso de existe).

Há também um existe semelhante ao content, mas que retorna true somente se o objeto result contiver um resultado para esse caminho/índice e a operação correspondente tiver sido bem-sucedida.

O código acima imprime:

Operações de mutação

Há mais variedades de operações de mutação. Algumas são feitas sob medida para lidar com matrizes, enquanto outras são mais adaptadas para lidar com dicionários.

Mais uma vez, fornecemos um construtor para direcionar mutações em um documento JSON específico por meio de bucket.mutateIn(String key). Você encadeia as operações que deseja executar e, por fim, chama executar() para realizar o conjunto de mutações.

As mutações podem levar em conta o CAS do documento anexo, verificando o CAS fornecido em relação ao atual antes de aplicar todo o conjunto de mutações. Para fazer isso, forneça o CAS a ser verificado, chamando .withCas(long cas) uma vez em sua cadeia de construtores.

Outros com Os métodos (que só precisam ser chamados uma vez) são:

  • withDurability(PersistTo p, ReplicateTo r)permite observar uma restrição de durabilidade em todo o conjunto de mutações.
  • withExpiry(int ttl)Permite dar ao documento um prazo de validade quando a mutação for bem-sucedida.

Além disso, algumas mutações permitem criar objetos mais profundos (por exemplo, criar a entrada no caminho newDict.sub.entry, apesar de newDict e submarino não existente). Isso é representado pelo símbolo createParents nos métodos do construtor.

Tomando o exemplo acima e usando algumas das operações de mutação, podemos fazer o seguinte com eficiência:

  1. Substituir a fruta ananas (que é incorretamente uma palavra francesa) com abacaxi.
  2. Adicionar uma nova fruta, pera no frente da matriz de frutas.
  3. Adicionar uma nova entrada a submarino chamado novoValor.
  4. Incrementar a contador por um delta de 100.
  5. Livre-se do lixo grande matriz.
  6. Aguarde até que o cbserver confirme que os dados foram gravados no disco do mestre.
  7. Abortar tudo se o CAS no servidor não for 1234.

Veja como fazer isso usando o Java SDK:

Outras operações de mutação disponíveis são:

  • upsert
  • arrayInsert (especializado na inserção de um valor em uma matriz, em um índice específico)
  • arrayAppend (especializado na inserção de um valor no final de uma matriz)
  • arrayInsertAll (o mesmo que arrayInsert, mas inserindo cada elemento de uma coleção na matriz)
  • arrayPrependAll (o mesmo que arrayPrepend, mas adicionando cada elemento de uma coleção à frente de uma matriz)
  • arrayAppendAll (o mesmo que arrayAppend, mas adicionando cada elemento de uma coleção à parte de trás de uma matriz)
  • arrayAddUnique (especializado em inserir um valor em uma matriz se o valor ainda não estiver presente na matriz)

Depois de aplicar essas 5 mutações, eis a aparência do documento no banco de dados:

Ao contrário do que acontece quando você faz várias pesquisas, se alguma das mutações falhar, todo o conjunto de operações será ignorado e nenhuma mutação será executada. Nesse caso, você receberá uma mensagem MultiMutationException no qual você pode verificar o índice da primeira operação com falha (bem como o status de erro correspondente).

Tratamento de erros

Cada operação de subdocumento pode levar a erros relacionados ao subdocumento: e se o documento que corresponde à chave fornecida não for JSON? E se você fornecer um caminho que não existe? Ou se o caminho contiver um índice de matriz em um elemento que não é uma matriz (por exemplo. sub[1])?

Todos os erros específicos de subdoc têm um Status da resposta no Java SDK e uma subclasse dedicada de SubDocumentException. Essas exceções são consistentes nos SDKs que oferecem uma API para subdocumentos:

A lista completa no Java SDK é:

  • PathNotFoundException
  • PathExistsException
  • NumberTooBigException
  • PathTooDeepException
  • PathMismatchException
  • ValueTooDeepException
  • DeltaTooBigException
  • CannotInsertValueException
  • PathInvalidException
  • DocumentNotJsonException*
  • DocumentTooDeepException*
  • MultiMutationException*

Os três últimos são de nível de documento (o que significa que se aplicam a todo o documento, sem considerar os caminhos individuais), de modo que sempre serão lançados diretamente pelo executar() métodos.

Os outros também podem ser lançados ao chamar Fragmento de documento's conteúdo nos casos em que você especificou várias operações de pesquisa.

Como dito na seção anterior, várias operações de mutação em que pelo menos uma falha acionam um MultiMutationException sendo lançada. Essa exceção tem um firstFailureIndex() e firstFailureStatus() para obter informações sobre qual especificação causou a falha de toda a operação.

Conclusão

Esperamos que você encontre ótimos casos de uso para esse novo recurso e que o adore! Então, pegue o Couchbase 4.5 Betabrinque com a API e não hesite em nos informar feedback!

Nesse meio tempo, Codificação feliz! – A equipe do Java SDK

Compartilhe este artigo
Receba atualizações do blog do Couchbase em sua caixa de entrada
Esse campo é obrigatório.

Autor

Postado por Simon Basle, engenheiro de software, Pivotal

Simon Basl_ é um engenheiro de software baseado em Paris que trabalha na equipe Spring da Pivotal. Anteriormente, ele trabalhou na equipe do Couchbase Java SDK. Seus interesses abrangem aspectos de design de software (OOP, padrões de design, arquitetura de software), clientes avançados, o que está além do código (integração contínua, (D)VCS, práticas recomendadas) e programação reativa. Ele também é editor da versão francesa do InfoQ.com.

2 Comentários

  1. Obrigado pela postagem. No entanto, tenho uma dúvida com relação ao manuseio da matriz: Existe a possibilidade de endereçar os elementos da matriz além de sua posição na matriz, de modo que os IDs em subdocumentos não possam ser usados para acessar os elementos?

  2. Estou usando este código
    DocumentFragment result = couchbaseBucket.async().lookupIn(docId).get(subDocId).execute().
    toBlocking().singleOrDefault(null);

    Não sei bem por que, mas result.rawContent(subDocId) retorna nulo, enquanto result.content(subDocId) retorna o valor correto.

    Você não poderia indicar a área que pode estar causando esse problema?

Deixe um comentário

Pronto para começar a usar o Couchbase Capella?

Iniciar a construção

Confira nosso portal do desenvolvedor para explorar o NoSQL, procurar recursos e começar a usar os tutoriais.

Use o Capella gratuitamente

Comece a trabalhar com o Couchbase em apenas alguns cliques. O Capella DBaaS é a maneira mais fácil e rápida de começar.

Entre em contato

Deseja saber mais sobre as ofertas do Couchbase? Deixe-nos ajudar.