2012-05-17 2 views
1

У меня есть таблица следов со следующей структурой
id | country_iso | object_id | created_at
Каждый объект может иметь множество записей для одного или более страны. Мне нужно выяснить, сколько объектов сейчас в каждой стране.
Я не могу просто сгруппировать его по country_iso, потому что в этом случае я получу количество записей для каждой страны, но не количество объектов.
Я не могу сгруппировать его по country_iso и object_id, потому что за это время я получу количество записей для каждого объекта в каждой стране.Группировка запросов для Монго и рельсов

Итак, кажется, мне нужно получить последнюю запись для каждого объекта, а затем сгруппировать по странам и получить количество. Также мне нужно избегать случаев, когда последняя запись имеет country_iso, равную null. Поэтому, если последняя запись для объекта равна null, мы должны получить запись до последнего и, следовательно, одну (так, последняя с нулевым значением country_iso).

Пример:

1 | US | 1 | 25.02.02 
2 | null | 1 | 26.02.02 
3 | UK | 2 | 25.02.02 
4 | UK | 3 | 25.02.02 
5 | UK | 4 | 25.02.02 
6 | US | 4 | 26.02.02 ` 

Результат будет

US | 2 
UK | 2 

Заранее спасибо за любые идеи.
P.S .: Обратите внимание, что имеется много данных (более 100 000 объектов и более 10 записей для каждого), и оно находится на удаленном сервере. Таким образом, я не могу получить данные и как-то пересчитать их, используя ruby ​​на главном сервере.

+0

100 000? Возможно, вы сможете сделать это в Ruby, если вам нужно делать это часто ...! –

+0

Я должен сделать это один раз (по крайней мере, это было запрошено как раз-только для данных) – RaskolnikOFF

ответ

1

Вам понадобится карта-сокращение или более короткая групповая версия.

http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Group

http://api.mongodb.org/ruby/current/Mongo/Collection.html#group-instance_method

https://github.com/mongodb/mongo-ruby-driver/blob/master/lib/mongo/collection.rb

Вот выстрел в коде:

MyModel.collection.group(
    :key  => :country_iso 
    :initial => { :object_id_set => {} }, 
    :reduce => 'function (obj,prev) { prev.object_id_set[obj.object_id] = 1; }', 
    :finalize => 'function (final) { final.object_count = keys(final.object_id_set).length }' 
) 
0

Менее умный способ является злоупотреблять distinct ...

counts = MyModel.distinct(:country_iso).map do |country_iso| 
    count = MyModel.where(:country_iso => country_iso).distinct(:object_id).count 
    [country_iso, count] 
end 

... хотя это 1 запрос для каждой страны. Не может быть ужасным @ 1ms за запрос.

+0

Интересная мысль, спасибо. Но кажется, что это не очень хорошо, потому что в этом случае в каждой стране может появиться какой-то объект. Для моего примера это будет 'US => 2, null => 1, UK => 3' – RaskolnikOFF

Смежные вопросы