Получение последнего документа ограниченного результата запроса Mongoid и .count()

Я использую Mongoid для работы с MongoDB. Все отлично, мне очень нравится и тд. В моем приложении для блога (контроллер сообщений, действие индекса) у меня есть этот код:

@posts = Post.without(:comments)
@posts = @posts.my_search(params[:s]) if params[:s]
@posts = @posts.order_by([:created_at, :desc])
@posts = @posts.where(:pid.lt => params[:p].to_i+1) if params[:p]
@posts = @posts.limit(items_per_page+1)

Часть с «где» — это реализация моего собственного метода разбивки на страницы (позволяет выводить результаты только в одном направлении, но без skip(), что я считаю плюсом). Теперь есть несколько небольших проблем, которые заставляют меня чувствовать себя некомфортно:

Чтобы моя разбивка на страницы работала, мне нужно получить последний пост в пределах этого лимита. Но когда я делаю @posts.last, я получаю последний документ всего запроса без ограничений. Хорошо, это странно, но не большая проблема. Кроме этого, результаты запроса действуют как почти обычный массив, поэтому в данный момент я получаю последний элемент с @posts.pop (забавно, но он не удаляет документы) или @posts.fetch(-1)

У меня такое чувство, что это не "правильный путь" и должно быть что-то более элегантное. Также @posts.count генерирует второй запрос точно так же, как и первый (без ограничений), но только с «количеством», и мне это не нравится.

Если я сделаю последнюю строку похожей на

@posts = @posts.limit(items_per_page+1).to_ary

чтобы преобразовать результаты запроса в массив, все генерирует только один запрос (хорошо), но теперь @posts.count перестает сообщать то, что мне нужно (общее количество документов без примененного ограничения) и ведет себя точно так же, как @posts.size - возвращает items_per_page+1 или меньше (плохо).

Итак, вот мои вопросы:

1) Каков "правильный" способ получить последний документ результатов запроса в пределах заданного лимита?

2) Как получить общее количество документов с заданными условиями без создания дополнительного запроса?

УПД:

3) @posts.first генерирует дополнительный запрос, как его предотвратить и просто получить первый документ, прежде чем я переберу все документы?


person Jake Jones    schedule 09.06.2011    source источник


Ответы (1)


Получение последнего документа:

Post.last 

Получение последнего документа с некоторыми другими запросами:

Post.order_by([:created_at, :desc]).last

Получение общего количества документов:

Post.order_by([:created_at, :desc]).count

Рекомендация: просто используйте встроенную нумерацию страниц.

@posts = Post.limit(10).paginate(:page=>pararms[:page])

позже:

<%= will_paginate @posts %>

Что касается дополнительных запросов - mongoid lazy загружает все:

@posts = Post.all #no query has been run yet
@posts.first #Ok, a query has finally been run because you are accessing the objects
person Jesse Wolgamott    schedule 09.06.2011
comment
Вы отвечаете на вопросы, которых я не задавал :) Добавьте .limit(2) перед .last и посмотрите, как это будет себя вести. Также .count генерирует дополнительный запрос, и я спрашивал, как этого избежать. Я удалил will_paginate и kaminari, потому что мне не нравится skip(), а также потому, что они не позволяют переходить к определенному посту в действии index. Кроме того, попробуйте выполнить итерацию с @posts.each после @post.first, вы увидите 2 запроса. - person Jake Jones; 09.06.2011
comment
Если вы хотите иметь только один запрос, вам нужно поместить все в массив. @posts = Post.whatever.all.to_a ... тогда @posts.first и @posts.last будут методами рубинового перечислителя, а не монгоидными командами. - person Jesse Wolgamott; 09.06.2011
comment
Да, я писал об этом в своем вопросе, но @posts.count генерирует дополнительный запрос, если я выполняю его до to_ary, и возвращает только ограниченную сумму, если я выполняю его после. Есть ли способ выполнить запрос и подсчитать результаты перед limit()? - person Jake Jones; 09.06.2011
comment
Сначала вам нужно будет вызвать to_a. Так что нет. - person Jesse Wolgamott; 09.06.2011