3.2.2. 视图排序¶
3.2.2.1. 基础¶
视图函数指定要为每行返回的键和值。CouchDB按此键整理视图行。在下面的示例中 LastName
属性作为键,因此结果将按 LastName
:
function(doc) {
if (doc.Type == "customer") {
emit(doc.LastName, {FirstName: doc.FirstName, Address: doc.Address});
}
}
CouchDB允许将任意JSON结构用作键。可以使用JSON数组作为键对排序和分组进行细粒度控制。
3.2.2.2. 实例¶
下面的巧妙技巧将同时返回客户和订单文档。密钥由一个客户组成 _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
.
3.2.2.3. 按日期排序¶
以人类可读的格式存储日期属性可能比较方便(例如,作为 string ),但仍按日期排序。这可以通过将日期转换为 number 在 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日期解析器兼容,因此您可以使用 new Date(doc.created_at)
在客户端JavaScript中,使日期排序在浏览器中更容易。
3.2.2.4. 字符串范围¶
如果需要用给定前缀包含每个字符串的起始键和结束键,则最好使用高值Unicode字符,而不是使用 'ZZZZ'
后缀。
也就是说,而不是:
startkey="abc"&endkey="abcZZZZZZZZZ"
你应该使用:
startkey="abc"&endkey="abc\ufff0"
3.2.2.5. 校对规范¶
本节基于中的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 它实现了 Unicode Collation Algorithm ,给字典排序键。如果您希望使用ASCII排序,这可能会产生令人惊讶的结果。请注意:
- 所有符号都在数字和字母之前排序(即使是像颚化符这样的“高位”符号,
0x7e
) - 不同字母序列的比较不考虑大小写,因此
a < aa
而且A < aa
和a < AA
- 相同的字母序列是按大小写比较的,大写之前是小写,所以
a < A
您可以演示7位ASCII字符的排序顺序,如下所示:
require 'rubygems'
require 'restclient'
require 'json'
DB="http://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
3.2.2.5.1. 关键范围¶
查询键范围时要特别小心。例如:查询:
startkey="Abc"&endkey="AbcZZZZ"
将匹配“ABC”和“abc1”,但不匹配“ABC”。这是因为UCA的分类如下:
abc < Abc < ABC < abc1 < AbcZZZZZ
对于大多数应用程序,为了避免问题,应该将 startkey ::
startkey="abc"&endkey="abcZZZZZZZZ"
将匹配以开头的所有键 [aA][bB][cC]
3.2.2.5.2. 复杂键¶
质询 startkey=["foo"]&endkey=["foo",{{}}]
将大多数数组键与第一个元素中的“foo”匹配,例如 ["foo","bar"]
和 ["foo",["bar","baz"]]
. 但是它不匹配 ["foo",{{"an":"object"}}]
3.2.2.6. _all_docs¶
这个 _all_docs 视图是一种特殊情况,因为它对doc id使用ASCII排序规则,而不是UCA::
startkey="_design/"&endkey="_design/ZZZZZZZZ"
找不到 _design/abc
因为 'Z' 在前面 'a' 在ASCII序列中。更好的解决方案是:
startkey="_design/"&endkey="_design0"
3.2.2.7. 原始排序规则¶
要从视图中挤出更多的性能,可以指定 "options":{{"collation":"raw"}}
在本地Erlang排序规则的视图定义中,尤其是在不需要UCA的情况下。这将提供不同的排序顺序:
1
false
null
true
{"a":"a"},
["a"]
"a"
当心那个 {{}}
不再是一个合适的“高”键哨兵值。使用一个字符串 "\ufff0"
相反。