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 User
registros, 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 User
registros 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 ActiveRecord
objetos desnecessários . Primeiro, usamos pluck
a id
coluna que retorna um id
para todos os User
registros. Em seguida, shuffle
selecionamos 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 User
registros 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()
order
SQL
ActiveRecord
SQL
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()")