Usar o Ruby para se conectar e executar comandos SQL no Azure Cosmos DB for PostgreSQL

APLICA-SE A: Azure Cosmos DB for PostgreSQL (da plataforma da extensão de dados Citus para PostgreSQL)

Este início rápido mostra como usar o código Ruby para conectar um cluster e usar as instruções SQL para criar uma tabela. Em seguida, você irá inserir, consultar, atualizar e excluir dados no banco de dados. As etapas neste artigo pressupõem que você esteja familiarizado com o desenvolvimento usando Ruby e que tenha começado a trabalhar recentemente com o Azure Cosmos DB for PostgreSQL.

Instalar a biblioteca PostgreSQL

Os exemplos de código neste artigo exigem o pg gem. Será necessário instalar o pg com o gerenciador de pacotes de idiomas (como bundler).

Conectar-se, criar uma tabela e inserir dados

Use o código a seguir para se conectar e criar uma tabela usando a instrução SQL CREATE TABLE e, em seguida, adicione linhas à tabela usando a instrução SQL INSERT INTO. O código usa um objeto PG::Connection com construtor para se conectar Azure Cosmos DB for PostgreSQL. Em seguida, ele chama o método exec() para executar os comandos DROP, CREATE TABLE e INSERT INTO. O código verifica erros usando a classe PG::Error. Em seguida, ele chama o método close() para fechar a conexão antes de encerrar.

No código, substitua <cluster> pelo nome do seu cluster e <password> pela senha do administrador.

require 'pg'
begin
    # NOTE: Replace <cluster> and <password> in the connection string.
    connection = PG::Connection.new("host=c-<cluster>.<uniqueID>.postgres.cosmos.azure.com port=5432 dbname=citus user=citus password=<password> sslmode=require")
    puts 'Successfully created connection to database'

    # Drop previous table of same name if one exists
    connection.exec('DROP TABLE IF EXISTS pharmacy;')
    puts 'Finished dropping table (if existed).'

    # Drop previous table of same name if one exists.
    connection.exec('CREATE TABLE pharmacy (pharmacy_id integer ,pharmacy_name text,city text,state text,zip_code integer);')
    puts 'Finished creating table.'

    # Insert some data into table.
    connection.exec("INSERT INTO pharmacy (pharmacy_id,pharmacy_name,city,state,zip_code) VALUES (0,'Target','Sunnyvale','California',94001);")
    connection.exec("INSERT INTO pharmacy (pharmacy_id,pharmacy_name,city,state,zip_code) VALUES (1,'CVS','San Francisco','California',94002);")
    puts 'Inserted 2 rows of data.'

    # Create index
    connection.exec("CREATE INDEX idx_pharmacy_id ON pharmacy(pharmacy_id);") 
rescue PG::Error => e
    puts e.message
ensure
    connection.close if connection
end

Distribuir tabelas

O Azure Cosmos DB for PostgreSQL oferece a superpotência da distribuição de tabelas entre vários nós, permitindo a escalabilidade. O comando abaixo permite a distribuição de uma tabela. Saiba mais sobre create_distributed_table e a coluna de distribuição aqui.

Observação

A distribuição de tabelas permite que elas cresçam em todos os nós de trabalho adicionados ao cluster.

Use o código a seguir para se conectar ao banco de dados e distribuir a tabela. No código, substitua <cluster> pelo nome do seu cluster e <password> pela senha do administrador.

require 'pg'
begin
    # NOTE: Replace <cluster> and <password> in the connection string.
    connection = PG::Connection.new("host=c-<cluster>.<uniqueID>.postgres.cosmos.azure.com port=5432 dbname=citus user=citus password=<password> sslmode=require")
    puts 'Successfully created connection to database.'

    # Super power of distributed tables.
    connection.exec("select create_distributed_table('pharmacy','pharmacy_id');") 
rescue PG::Error => e
    puts e.message
ensure
    connection.close if connection
end

Ler dados

Use o código a seguir para conectar-se e ler os dados usando uma instrução SQL SELECT.

O código chama o método exec() para executar o comando SELECT, mantendo os resultados em um conjunto de resultados. A coleção do conjunto de resultados é iterada por meio do loop resultSet.each, mantendo os valores da linha atual na variável de linha. No código, substitua <cluster> pelo nome do seu cluster e <password> pela senha do administrador.

require 'pg'
begin
    # NOTE: Replace <cluster> and <password> in the connection string.
    connection = PG::Connection.new("host=c-<cluster>.<uniqueID>.postgres.cosmos.azure.com port=5432 dbname=citus user=citus password=<password> sslmode=require")
    puts 'Successfully created connection to database.'

    resultSet = connection.exec('SELECT * from pharmacy')
    resultSet.each do |row|
        puts 'Data row = (%s, %s, %s, %s, %s)' % [row['pharmacy_id'], row['pharmacy_name'], row['city'], row['state'], row['zip_code ']]
    end
rescue PG::Error => e
    puts e.message
ensure
    connection.close if connection
end

Atualizar dados

Use o código a seguir para conectar-se e atualizar os dados usando uma instrução SQL UPDATE. No código, substitua <cluster> pelo nome do seu cluster e <password> pela senha do administrador.

require 'pg'
begin
    # NOTE: Replace <cluster> and <password> in the connection string.
    connection = PG::Connection.new("host=c-<cluster>.<uniqueID>.postgres.cosmos.azure.com port=5432 dbname=citus user=citus password=<password> sslmode=require")
    puts 'Successfully created connection to database.'

    # Modify some data in table.
    connection.exec('UPDATE pharmacy SET city = %s WHERE pharmacy_id = %d;' % ['\'guntur\'',100])
    puts 'Updated 1 row of data.'
rescue PG::Error => e
    puts e.message
ensure
    connection.close if connection
end

Excluir dados

Use o código a seguir para conectar-se e excluir os dados usando uma instrução SQL DELETE. No código, substitua <cluster> pelo nome do seu cluster e <password> pela senha do administrador.

require 'pg'
begin
    # NOTE: Replace <cluster> and <password> in the connection string.
    connection = PG::Connection.new("host=c-<cluster>.<uniqueID>.postgres.cosmos.azure.com port=5432 dbname=citus user=citus password=<password> sslmode=require")
    puts 'Successfully created connection to database.'

    # Delete some data in table.
    connection.exec('DELETE FROM pharmacy WHERE city = %s;' % ['\'guntur\''])
    puts 'Deleted 1 row of data.'
rescue PG::Error => e
    puts e.message
ensure
    connection.close if connection
end

Comando COPY para ingestão superrápida

O comando COPY pode gerar uma taxa de transferência enorme ao ingerir dados no Azure Cosmos DB for PostgreSQL. O comando COPY pode ingerir dados em arquivos ou de microlotes de dados na memória para ingestão em tempo real.

Comando COPY para carregar dados de um arquivo

O código a seguir copia dados de um arquivo CSV para uma tabela de banco de dados. Ele exige o arquivo pharmacies.csv. No código, substitua <cluster> pelo nome do seu cluster e <password> pela senha do administrador.

require 'pg'
begin
    filename = String('pharmacies.csv')

    # NOTE: Replace <cluster> and <password> in the connection string.
    connection = PG::Connection.new("host=c-<cluster>.<uniqueID>.postgres.cosmos.azure.com port=5432 dbname=citus user=citus password=<password> sslmode=require")
    puts 'Successfully created connection to database.'

    # Copy the data from Csv to table.
    result = connection.copy_data "COPY pharmacy FROM STDIN with csv" do
        File.open(filename , 'r').each do |line|
            connection.put_copy_data line
        end
    puts 'Copied csv data successfully.'
    end      
rescue PG::Error => e
    puts e.message
ensure
    connection.close if connection
end

Comando COPY para carregar dados na memória

O código a seguir copia dados na memória em uma tabela. No código, substitua <cluster> pelo nome do seu cluster e <password> pela senha do administrador.

require 'pg'
begin
    # NOTE: Replace <cluster> and <password> in the connection string.
    connection = PG::Connection.new("host=c-<cluster>.<uniqueID>.postgres.cosmos.azure.com port=5432 dbname=citus user=citus password=<password> sslmode=require")
    puts 'Successfully created connection to database.'

    enco = PG::TextEncoder::CopyRow.new
    connection.copy_data "COPY pharmacy FROM STDIN", enco do
        connection.put_copy_data [5000,'Target','Sunnyvale','California','94001']
        connection.put_copy_data [5001, 'CVS','San Francisco','California','94002']
        puts 'Copied in-memory data successfully.'
    end
rescue PG::Error => e
    puts e.message
ensure
    connection.close if connection
end

Repetição de aplicativo para falhas de solicitação de banco de dados

Às vezes, as solicitações de banco de dados do aplicativo podem falhar. Esses problemas podem ocorrer em diferentes cenários, como falha de rede entre o aplicativo e o banco de dados, senha incorreta etc. Alguns problemas podem ser transitórios e serem resolvidos em alguns segundos ou minutos. Você pode configurar a lógica de repetição no aplicativo para corrigir os erros transitórios.

A configuração da lógica de repetição no aplicativo ajuda a aprimorar a experiência do usuário final. Em cenários de falha, os usuários vão apenas esperar um pouco mais para que o aplicativo atenda às solicitações, em vez de receber erros.

O exemplo abaixo mostra como implementar a lógica de repetição no aplicativo. O snippet de código de exemplo tenta uma solicitação de banco de dados a cada 60 segundos (até cinco vezes) até que ela seja bem-sucedida. O número e a frequência de repetições podem ser configurados com base nas necessidades do aplicativo.

No código, substitua <cluster> pelo nome do seu cluster e <password> pela senha do administrador.

require 'pg'

def executeretry(sql,retryCount)
  begin
    for a in 1..retryCount do
      begin
        # NOTE: Replace <cluster> and <password> in the connection string.
        connection = PG::Connection.new("host=c-<cluster>.<uniqueID>.postgres.cosmos.azure.com port=5432 dbname=citus user=citus password=<password> sslmode=require")
        resultSet = connection.exec(sql)
        return resultSet.each
      rescue PG::Error => e
        puts e.message
        sleep 60
      ensure
        connection.close if connection
      end
    end
  end
  return nil
end

var = executeretry('select 1',5)

if var !=nil then
  var.each do |row|
    puts 'Data row = (%s)' % [row]
  end
end

Próximas etapas