Нумерация страниц в CouchDB? - PullRequest
       31

Нумерация страниц в CouchDB?

43 голосов
/ 23 ноября 2008

Как мне поступить в реализации запросов, необходимых для нумерации страниц?

Обычно, когда запрашивается страница 1, получают первые 5 записей. Для страницы 2 получите следующие 5 и т. Д.

Я планирую использовать это через модуль couchdb-python, но это не должно иметь никакого значения для реализации.

Ответы [ 3 ]

31 голосов
/ 25 июня 2011

В справочнике CouchDB содержится хорошее обсуждение нумерации страниц, включая множество примеров кода, здесь: http://guide.couchdb.org/draft/recipes.html#pagination Вот их алгоритм:

  • Запрос rows_per_page + 1 строк из представления
  • Показать rows_per_page строк, сохранить последнюю строку как next_startkey
  • В качестве информации страницы сохраните startkey и next_startkey
  • Используйте значения next_* для создания следующей ссылки, а другие - для создания предыдущей ссылки

N.B .: Правильный способ извлечения страниц в CouchDB - это указать начальный ключ, а не начальный индекс, как вы думаете. Но как узнать, на каком ключе начать 2-ю страницу? Умное решение: «Вместо того, чтобы запрашивать 10 строк для страницы, вы запрашиваете 11 строк, но отображаете только 10 и используете значения в 11-й строке в качестве начального ключа для следующей страницы.»

Если вы ожидаете, что несколько документов будут выдавать идентичные ключи, вам нужно будет использовать startdocid в дополнение к startkey для правильного разбиения на страницы. Причина в том, что одного startkey уже будет недостаточно для однозначной идентификации строки. Эти параметры бесполезны, если вы не предоставите startkey. Фактически, CouchDB сначала будет смотреть на параметр startkey, затем он будет использовать параметр startdocid для дальнейшего переопределения начала диапазона, если несколько потенциальных начинающих строк имеют одинаковый ключ, но разные идентификаторы документа. То же самое для enddocid.

13 голосов
/ 24 ноября 2008

API CouchDB HTTP View предоставляет множество возможностей для эффективной подкачки страниц.

Самый простой метод будет использовать startkey и count. Count - это максимальное количество записей, которые CouchDB возвратит для этого запроса на просмотр, что соответствует вашему дизайну, и startkey - это то место, с которого вы хотите запустить CouchDB. Когда вы запрашиваете представление, оно также сообщает вам, сколько существует записей, позволяя подсчитать, сколько страниц будет, если вы хотите показать это пользователям.

Таким образом, в первом запросе не будет указана начальная клавиша, а будет только количество записей, которые вы хотите показать. Затем вы можете отметить ключ последней возвращенной записи и использовать его в качестве ключа запуска для следующей страницы. В этой простой форме вы получите перекрытие, при котором последняя запись на одной странице является первой из следующей. Если это нежелательно, просто не отображать последнюю запись на странице.

Более простой способ сделать это - использовать параметр skip для разработки начального документа для страницы, однако этот метод следует использовать с осторожностью. Параметр skip просто заставляет внутренний движок не возвращать записи, которые он перебирает. Хотя это дает желаемое поведение, это намного медленнее, чем поиск первого документа для страницы по ключу. Чем больше документов будет пропущено, тем медленнее будет запрос.

1 голос
/ 23 ноября 2008

Это то, что я придумал до сих пор - получить идентификаторы всех сообщений, а затем получить фактические элементы для первого x количества идентификаторов.

Это не очень эффективно, но больше, чем извлечение всех сообщений и отбрасывание большей части. Тем не менее, к моему удивлению, он запускался довольно быстро - я запускал метод posthelper.page() 100 раз, и это заняло около 0,5 секунды.

Я не хотел публиковать это в актуальном вопросе, так что это не повлияло бы на ответы так сильно - вот код:

allPostsUuid = """
function(doc) {
if(doc.type == 'post'){
    emit(doc._id, null);
}
}
"""

class PostsHelper:
    def __init__(self):
        server = Server(config.dbhost)
        db = server[config.dbname]
        return db


    def _getPostByUuid(self, uuid):
        return self.db.get(uuid)

    def page(self, number = 1):
        number -= 1 # start at zero offset
        start = number * config.perPage
        end = start + config.perPage

        allUuids = [
            x.key for x in self.db.query(allPostsUuid)
        ]
        ret = [
            self._getPostByUuid(x) for x in allUuids[start : end]
        ]

        if len(ret) == 0:
            raise Error404("Invalid page (%s results)" % (len(allUuids)))
        else:
            return ret
...