可以說我有一個用戶集合。有沒有使用mongoid在集合中找到n個隨機用戶的方式,它不會將同一用戶返回兩次?現在可以說用戶集合看起來像這樣:Mongoid隨機文檔
class User
include Mongoid::Document
field :name
end
簡單吧?
謝謝
可以說我有一個用戶集合。有沒有使用mongoid在集合中找到n個隨機用戶的方式,它不會將同一用戶返回兩次?現在可以說用戶集合看起來像這樣:Mongoid隨機文檔
class User
include Mongoid::Document
field :name
end
簡單吧?
謝謝
最好的解決方案將取決於預期的集合大小。
對於小集合,只需將它們全部和.shuffle.slice!
對於n的尺寸小,你可以用這樣的僥倖:
result = (0..User.count-1).sort_by{rand}.slice(0, n).collect! do |i| User.skip(i).first end
對於大尺寸的n,我建議建立一個「隨機」列進行排序。看到這裏的細節:
http://cookbook.mongodb.org/patterns/random-attribute/
https://github.com/mongodb/cookbook/blob/master/content/patterns/random-attribute.txt
謝謝......這可能是矯枉過正,但想知道是否有一種簡單的方法將其轉換回Mongoid :: Criteria – GTDev
SQL有ORDER BY RAND(),但據我所知在mongodb中沒有相應的東西。所以你可以創建「隨機」列,然後創建User.order_by,這將是一個單一的查詢。 –
根據[SO:MongoDB查找隨機數據集的性能](http://stackoverflow.com/questions/9434969/mongodb-find-random-dataset-performance),對於大值,「skip」效率不是很高:「Skip強制Mongo遍歷結果集,直到找到您要查找的文檔,因此查詢的結果集越大,所需時間就越長。「 (這支持丹的回答。) –
您可以通過
代碼
>> cnt = User.count
=> 10
>> n = 5
=> 5
>> offset = 0
=> 0
>> if n<cnt
>> offset = rand(cnt-n)
>> end
>> 2
>> User.skip(offset).limit(n)
,你可以把這個方法
def get_random_users(n)
offset = 0
cnt = User.count
if n < cnt
offset = rand(cnt-n)
end
User.skip(offset).limit(n)
end
,並調用它像
rand_users = get_random_users(5)
希望這個他LPS
謝謝。但這真的是隨機的。我想這將提供從cnt到cnt + n的隨機範圍,但不會創建一個條件。例如如果用戶5被選擇......那麼用戶6將很有可能在用戶11將是零的機率的同時? – GTDev
對,這是從我的答案中折中。如果你可以從隨機點開始,只需選擇下一個n個連續記錄,那麼你可以在一個查詢中執行它,而不是在n個查詢中執行。然後,您可以將結果隨機混合,使其在該選擇內隨機化。但是,不,這不是隨機的。 –
如果你真的想要簡單,你可以用這個來代替:
class Mongoid::Criteria
def random(n = 1)
indexes = (0..self.count-1).sort_by{rand}.slice(0,n).collect!
if n == 1
return self.skip(indexes.first).first
else
return indexes.map{ |index| self.skip(index).first }
end
end
end
module Mongoid
module Finders
def random(n = 1)
criteria.random(n)
end
end
end
你只需要調用User.random(5)
,你會得到5級隨機的用戶。 它也適用於過濾,所以如果你只想註冊用戶,你可以做User.where(:registered => true).random(5)
。
對於大型館藏,這需要一段時間,所以我建議使用一種替代方法,在這種方法中,您將隨機劃分一個計數(例如:25 000到30 000)並隨機化該範圍。
因爲我要保持一個標準,我做的:
scope :random, ->{
random_field_for_ordering = fields.keys.sample
random_direction_to_order = %w(asc desc).sample
order_by([[random_field_for_ordering, random_direction_to_order]])
}
我覺得這是更好地專注於隨機返回的結果集,所以我嘗試:
Model.all.to_a.shuffle
希望這有助於。如果您想根據一些標準來尋找隨機模型
random_model = Model.skip(rand(Model.count)).first
:
如果數據庫中有一百萬個'Model'實例,那麼這將會非常可怕。 –
這只是一個例子。您應該首先獲得您正在查找的結果集。 –
如果你只是想一個文檔,並且不希望定義一個新的標準方法,你可能只是這樣做
criteria = Model.scoped_whatever.where(conditions) # query example
random_model = criteria.skip(rand(criteria.count)).first
@moox的方法非常有趣,但我懷疑monkeypatching整個Mongoid在這裏是個好主意。所以我的方法只是寫一個關於Randomizable
的問題,它可以包含在您使用此功能的每個模型中。這正好app/models/concerns/randomizeable.rb
:
module Randomizable
extend ActiveSupport::Concern
module ClassMethods
def random(n = 1)
indexes = (0..count - 1).sort_by { rand }.slice(0, n).collect!
return skip(indexes.first).first if n == 1
indexes.map { |index| skip(index).first }
end
end
end
然後你User
模式是這樣的:
class User
include Mongoid::Document
include Randomizable
field :name
end
而且測試....
require 'spec_helper'
class RandomizableCollection
include Mongoid::Document
include Randomizable
field :name
end
describe RandomizableCollection do
before do
RandomizableCollection.create name: 'Hans Bratwurst'
RandomizableCollection.create name: 'Werner Salami'
RandomizableCollection.create name: 'Susi Wienerli'
end
it 'returns a random document' do
srand(2)
expect(RandomizableCollection.random(1).name).to eq 'Werner Salami'
end
it 'returns an array of random documents' do
srand(1)
expect(RandomizableCollection.random(2).map &:name).to eq ['Susi Wienerli', 'Hans Bratwurst']
end
end
MongoDB的3.2談到與$sample
救援(link to doc)
編輯:最近Mongoid已實現$樣本,這樣你就可以調用mongoid
Mongoid的YourCollection.all.sample(5)
以前的版本不支持sample
直到Mongoid 6,所以你要運行這個與蒙戈司機彙總查詢:
samples = User.collection.aggregate([ { '$sample': { size: 3 } } ])
# call samples.to_a if you want to get the objects in memory
您可以用
01做些什麼我相信functionnality應該很快Mongoid做它的方式,但在此期間
module Utility
module_function
def sample(model, count)
ids = model.collection.aggregate([
{ '$sample': { size: count } }, # Sample from the collection
{ '$project': { _id: 1} } # Keep only ID fields
]).to_a.map(&:values).flatten # Some Ruby magic
model.find(ids)
end
end
Utility.sample(User, 50)
這是由MongoDB的團隊考慮。他們根據需求優先考慮問題;所以如果你想要這個功能,請查看[Ticket#533:從Collection中獲取隨機項目](https://jira.mongodb.org/browse/SERVER-533),閱讀並相應投票。 –
票已關閉,現在有一個MongoDB的'sample'運算符。似乎沒有整合到Mongoid,但查詢必須手動完成。你可能也想看看'snapshot'來真正避免併發的重複。 –