Dicas rápidas do Rails – registros aleatórios

Aleatória

A ordenação de registros retornados do ActiveRecord de maneira aleatória está em questão hoje.

Cenário: quero retornar 5 usuários aleatórios

Como faríamos para resolver isso? Bem, talvez uma primeira passagem fosse parecida com isso?

User.all.shuffle[0..4]

Portanto, nesta primeira passagem, estamos pegando todos os Userregistros, embaralhando-os e, em seguida, pegando os primeiros 5 registros. Isso resolve o problema, mas por que faríamos algo diferente?

Primeiro, estamos retornando todos os User registros apenas para retornar 5! Fazer algo assim é quase sempre uma má ideia, especialmente ao lidar com Userregistros de tipo. É provável que eles tenham uma alta contagem de registros em seu aplicativo. Quando você devolve todos, cada um está ocupando memória só para você devolver 5.

Vamos aliviar um pouco esse problema com outra solução.

ids = User.pluck(:id).shuffle[0..4]
User.where(id: ids)

Agora estamos fazendo uma chamada extra ao banco de dados em favor de não retornar um monte de ActiveRecordobjetos desnecessários . Primeiro, usamos plucka idcoluna que retorna um idpara todos os Userregistros. Em seguida, shuffleselecionamos esse array e escolhemos os 5 primeiros registros.

Bem, isso é muito bom, estamos salvando nossa memória para os registros que realmente queremos. Isso novamente resolve nosso problema, mas é um pouco mais para olhar (com a chamada DB extra).

Podemos aliviar um pouco esse problema com outra solução.

# postgresql
User.limit(5).order("RANDOM()")

Vamos revisar o que está acontecendo aqui. Estamos consultando Userregistros ordenados aleatoriamente e limitando o conjunto de retorno a 5 resultados. Nosso problema original a ser resolvido era: Eu quero retornar 5 usuários aleatórios. Não apenas escrevemos código para resolver esse problema, mas o código escrito é expresso de forma muito próxima ao que gostaríamos se fosse lido em voz alta.

O que mudou? A principal diferença é o passado para . Para quem acha que isso parece um pouco estranho, esta é uma função específica do banco de dados. Você pode passar todos os tipos de fragmentos para que apenas se juntem para fazer uma declaração completa . Este é apenas outro fragmento. A chamada que está sendo feita realmente se parece com isto:RANDOM()orderSQLActiveRecordSQL

SELECT * FROM users ORDER BY RANDOM() LIMIT 5

Agora eu sei o que você pode estar pensando … “ActiveRecord é agnóstico de banco de dados! Por que você se vincularia a uma implementação específica !?” A resposta simples é sim, ActiveRecordé independente do banco de dados e, sim, é ótimo. Ele dá ao desenvolvedor a opção de escolher qual banco de dados é melhor para resolver seus problemas específicos. Agora, pense que, uma vez feita sua escolha de banco de dados, com que freqüência, se é que algum dia, você fará uma alteração em outro? Os bancos de dados são muito bons no que foram feitos para fazer … que eles sejam bons nisso. Não tenha medo de usar funções e recursos específicos de banco de dados para melhorar seu desenvolvimento. Este exemplo particular nos foi concedido pelo PostgreSQL , que é meu banco de dados preferido.

Não está usando PostgreSQL? Essa funcionalidade semelhante pode ser obtida pela maioria dos bancos de dados. Consulte sua documentação. Aqui está um exemplo do MySQL para mostrar como a mesma funcionalidade pode ser obtida:

# mysql
User.limit(5).order("RAND()")

Artigo original