Spec-Zone.ru › CouchDB 3.5

Сортировка представлений

Основы

Функции представлений задают ключ и значение, возвращаемые для каждой строки. CouchDB сортирует строки представления по этому ключу. В следующем примере свойство LastName служит ключом, поэтому результат будет отсортирован по LastName:

function(doc) {
    if (doc.Type == "customer") {
        emit(doc.LastName, {FirstName: doc.FirstName, Address: doc.Address});
    }
}

CouchDB позволяет использовать в качестве ключей произвольные структуры JSON. Для точного управления сортировкой и группировкой можно использовать массивы JSON.

Примеры

Следующий остроумный прием позволяет получить и документы клиентов, и документы заказов. Ключ состоит из _id клиента и токена сортировки. Поскольку ключ документов заказов начинается с _id документа клиента, все заказы будут отсортированы по клиентам. Поскольку токен сортировки для клиентов меньше токена для заказов, документ клиента будет располагаться перед связанными с ним заказами. Значения 0 и 1 для токена сортировки выбраны произвольно.

function(doc) {
    if (doc.Type == "customer") {
        emit([doc._id, 0], null);
    } else if (doc.Type == "order") {
        emit([doc.customer_id, 1], null);
    }
}

Чтобы вывести конкретного клиента с _id XYZ и все заказы этого клиента, ограничьте диапазоны startkey и endkey так, чтобы они охватывали только документы для _id этого клиента:

startkey=["XYZ"]&endkey=["XYZ", {}]

Не рекомендуется возвращать сам документ в представлении. Вместо этого, чтобы включить содержимое документов при запросе представления, запросите представление с параметром ?include_docs=true.

Сортировка по датам

Может быть удобно хранить атрибуты даты в удобочитаемом формате (то есть как строку), но при этом сортировать по дате. Для этого можно преобразовать дату в число в функции emit(). Например, для документа с атрибутом created_at, равным 'Wed Jul 23 16:29:21 +0100 2013', следующая функция emit выполнит сортировку по дате:

emit(Date.parse(doc.created_at).getTime(), null);

Кроме того, если используется формат даты, который сортируется лексикографически, например "2013/06/09 13:52:11 +0000", можно просто

emit(doc.created_at, null);

и обойтись без преобразования. Бонус: этот формат даты совместим с анализатором дат JavaScript, поэтому в клиентском JavaScript можно использовать new Date(doc.created_at), чтобы упростить сортировку дат в браузере.

Диапазоны строк

Если нужны начальный и конечный ключи, охватывающие все строки с заданным префиксом, лучше использовать символ Юникода с высоким значением, а не суффикс 'ZZZZ'.

То есть вместо:

startkey="abc"&endkey="abcZZZZZZZZZ"

следует использовать:

startkey="abc"&endkey="abc\ufff0"

Спецификация сортировки

Этот раздел основан на функции view_collation из view_collation.js:

// special values sort before all other types
null
false
true

// then numbers
1
2
3.0
4

// then text, case sensitive
"a"
"A"
"aa"
"b"
"B"
"ba"
"bb"

// then arrays. compared element by element until different.
// Longer arrays sort after their prefixes
["a"]
["b"]
["b","c"]
["b","c", "a"]
["b","d"]
["b","d", "e"]

// then object, compares each key value in the list until different.
// larger objects sort after their subset objects.
{a:1}
{a:2}
{b:1}
{b:2}
{b:2, a:1} // Member order does matter for collation.
           // CouchDB preserves member order
           // but doesn't require that clients will.
           // this test might fail if used with a js engine
           // that doesn't preserve order
{b:2, c:2}

Сравнение строк выполняется с помощью ICU, реализующей алгоритм сортировки Юникода, который обеспечивает сортировку ключей в словарном порядке. Это может привести к неожиданным результатам, если вы рассчитывали на порядок ASCII. Обратите внимание:

  • Все символы располагаются перед цифрами и буквами (в том числе «старшие» символы, например тильда, 0x7e)

  • Различающиеся последовательности букв сравниваются без учета регистра, поэтому a < aa, а также A < aa и a < AA

  • Одинаковые последовательности букв сравниваются с учетом регистра: строчные буквы идут перед прописными, поэтому a < A

Последовательность сортировки 7-битных символов ASCII можно продемонстрировать так:

require 'rubygems'
require 'restclient'
require 'json'

DB="http://adm:pass@127.0.0.1:5984/collator"

RestClient.delete DB rescue nil
RestClient.put "#{DB}",""

(32..126).each do |c|
    RestClient.put "#{DB}/#{c.to_s(16)}", {"x"=>c.chr}.to_json
end

RestClient.put "#{DB}/_design/test", <<EOS
{
    "views":{
        "one":{
            "map":"function (doc) { emit(doc.x,null); }"
        }
    }
}
EOS

puts RestClient.get("#{DB}/_design/test/_view/one")

Получается следующая последовательность сортировки:

` ^ _ - , ; : ! ? . ' " ( ) [ ] { } @ * / \ & # % + < = > | ~ $ 0 1 2 3 4 5 6 7 8 9
a A b B c C d D e E f F g G h H i I j J k K l L m M n N o O p P q Q r R s S t T u U v V w W x X y Y z Z

Диапазоны ключей

Будьте особенно внимательны при запросе диапазонов ключей. Например, запрос:

startkey="Abc"&endkey="AbcZZZZ"

найдет «ABC» и «abc1», но не «abc». Это связано с тем, что UCA сортирует так:

abc < Abc < ABC < abc1 < AbcZZZZZ

Чтобы избежать проблем в большинстве приложений, следует перевести startkey в нижний регистр:

startkey="abc"&endkey="abcZZZZZZZZ"

найдет все ключи, начинающиеся с [aA][bB][cC]

Составные ключи

Запрос startkey=["foo"]&endkey=["foo",{}] найдет большинство ключей-массивов, у которых первым элементом является «foo», например ["foo","bar"] и ["foo",["bar","baz"]]. Однако он не найдет ["foo",{"an":"object"}]

_all_docs

Представление _all_docs — особый случай: для идентификаторов документов оно использует сортировку ASCII, а не UCA:

startkey="_design/"&endkey="_design/ZZZZZZZZ"

не найдет _design/abc, потому что в последовательности ASCII «Z» идет перед «a». Лучше использовать следующий вариант:

startkey="_design/"&endkey="_design0"

Нативная сортировка

Чтобы немного повысить производительность представлений, можно указать "options":{"collation":"raw"} в определении представления для использования нативной сортировки Erlang, особенно если UCA не требуется. В этом случае последовательность сортировки будет другой:

1
false
null
true
{"a":"a"},
["a"]
"a"

Имейте в виду, что {} больше не подходит в качестве «верхнего» ключа-маркера. Вместо него используйте строку, например "\ufff0".

Copyright © 2025 The Apache Software Foundation — Licensed under the Apache License 2.0
https://docs.couchdb.org/en/3.5.1/ddocs/views/collation.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API