分页和书签
书签有助于发布结果集的下一页结果。 使用分页时,您可以高效地迭代一系列文档。
您可以使用 skip
/limit
模式 对结果集进行迭代,但它的速度会随着 skip
的值越大而逐渐变慢。
IBM Cloudant 查询 和 IBM Cloudant 搜索 都使用书签作为从结果集解锁下一页结果的键。 在称为 书签 的后续部分中完整描述了此实践。 由于无需密钥操作来制定下一个结果集的请求,因此管理起来不太复杂。 将第一个响应中接收到的书签传递到第二个请求。
现在,您可以看到一种更好的方法来浏览大型文档集。
使用 _all_docs
和视图进行页面调度
如果使用 GET
或 POST
$SERVICE_URL/$DATABASE/_all_docs
端点批量访存文档,那么可能会看到 limit
和 skip
参数。 通过使用这些参数,您可以定义要使用的文档数以及要从其开始的范围内的偏移量。 使用 skip
/limit
模式对结果进行迭代会起作用,但它的速度会逐渐慢于
skip
的值越大。
什么是 _all_docs
端点?
GET
和 POST
$SERVICE_URL/$DATABASE/_all_docs
用于从 IBM Cloudant 数据库的 主索引(即使每个文档的 _id
保持顺序的索引) 中访存数据。 _all_docs
端点采用一些可选参数,用于配置所请求的数据范围以及是否返回每个文档的主体。 如果未提供任何参数,那么 _all_docs
将流式传输数据库的所有文档,仅返回文档 _id
及其当前 _rev
令牌。
curl -H "Authorization: Bearer $API_BEARER_TOKEN" -X GET "$SERVICE_URL/orders/_all_docs"
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.AllDocsResult;
import com.ibm.cloud.cloudant.v1.model.PostAllDocsOptions;
Cloudant service = Cloudant.newInstance();
PostAllDocsOptions docsOptions =
new PostAllDocsOptions.Builder()
.db("orders")
.build();
AllDocsResult response =
service.postAllDocs(docsOptions).execute().getResult();
System.out.println(response);
const { CloudantV1 } = require('@ibm-cloud/cloudant');
const service = CloudantV1.newInstance({});
service.postAllDocs({
db: 'orders',
}).then(response => {
console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
response = service.post_all_docs(
db='orders',
).get_result()
print(response)
postAllDocsOptions := service.NewPostAllDocsOptions(
"orders",
)
allDocsResult, response, err := service.PostAllDocs(postAllDocsOptions)
if err != nil {
panic(err)
}
b, _ := json.MarshalIndent(allDocsResult, "", " ")
fmt.Println(string(b))
先前的 Go 示例需要以下导入块:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
)
所有 Go 示例都需要初始化 service
对象。 有关更多信息,请参阅 API 文档的 认证部分 以获取示例。
{
"total_rows": 11,
"offset": 0,
"rows": [
{
"id": "4eee973603bf77f30b1f880ed83df76a",
"key": "4eee973603bf77f30b1f880ed83df76a",
"value": {
"rev": "1-3b5e6b73e57745787ad5627fe8f268c1"
}
},
{
"id": "4eee973603bf77f30b1f880ed83f469a",
"key": "4eee973603bf77f30b1f880ed83f469a",
"value": {
"rev": "1-967a00dff5e02add41819138abb3284d"
}
}
...
如果提供 include_docs=true
,那么会将另一个 doc
属性添加到包含文档主体的结果集中的每个“行”。
limit
,startkey
和 endkey
参数
要在合理大小的页面中从 _all_docs
访问数据,必须提供 limit
参数以告知 IBM Cloudant 要返回的文档数:
# get me 5 documents
GET $SERVICE_URL/$DATABASE/_all_docs?limit=5 HTTP/1.1
您还可以通过向 startkey
或 endkey
提供一个或多个值来限制所需的文档 _id
的范围。
# get me 5 documents from _id order00057 onwards
curl -H "Authorization: Bearer $API_BEARER_TOKEN" "$SERVICE_URL/orders/_all_docs?limit=5&startkey=\"order00057\"" \
# get me 5 documents between _id order00057 --> order00077
curl -H "Authorization: Bearer $API_BEARER_TOKEN" "$SERVICE_URL/orders/_all_docs?limit=5&startkey=\"order00057\"&endkey=\"order00077\"" \
# get me 5 documents up to _id order00077
curl -H "Authorization: Bearer $API_BEARER_TOKEN" "$SERVICE_URL/orders/_all_docs?limit=5&endkey=\"order00077\""
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.AllDocsResult;
import com.ibm.cloud.cloudant.v1.model.PostAllDocsOptions;
Cloudant service = Cloudant.newInstance();
// get me 5 documents from _id order00057 onwards
PostAllDocsOptions docsOptions =
new PostAllDocsOptions.Builder()
.db("orders")
.startKey("order00057")
.limit(5)
.build();
AllDocsResult response1 =
service.postAllDocs(docsOptions).execute().getResult();
System.out.println(response1);
// get me 5 documents between _id order00057 --> order00077
PostAllDocsOptions docsOptions2 =
new PostAllDocsOptions.Builder()
.db("orders")
.startKey("order00057")
.endKey("order00077")
.limit(5)
.build();
AllDocsResult response2 =
service.postAllDocs(docsOptions2).execute().getResult();
System.out.println(response2);
// get me 5 documents up to _id order00077
PostAllDocsOptions docsOptions3 =
new PostAllDocsOptions.Builder()
.db("orders")
.endKey("order00077")
.limit(5)
.build();
AllDocsResult response3 =
service.postAllDocs(docsOptions3).execute().getResult();
System.out.println(response3);
const { CloudantV1 } = require('@ibm-cloud/cloudant');
const service = CloudantV1.newInstance({});
// get me 5 documents from _id order00057 onwards
service.postAllDocs({
db: 'orders',
startKey: 'order00057',
limit: 5
}).then(response1 => {
console.log(response1.result);
});
// get me 5 documents from _id order00057 onwards
service.postAllDocs({
db: 'orders',
startKey: 'order00057',
endKey: 'order00077',
limit: 5
}).then(response2 => {
console.log(response2.result);
});
// get me 5 documents up to _id order00077
service.postAllDocs({
db: 'orders',
endKey: 'order00077',
limit: 5
}).then(response3 => {
console.log(response3.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
# get me 5 documents from _id order00057 onwards
response1 = service.post_all_docs(
db='orders',
start_key='order00057',
limit=5
).get_result()
print(response1)
# get me 5 documents between _id order00057 --> order00077
response2 = service.post_all_docs(
db='orders',
start_key='order00057',
end_key='order00077',
limit=5
).get_result()
print(response2)
# get me 5 documents up to _id order00077
response3 = service.post_all_docs(
db='orders',
end_key='order00077',
limit=5
).get_result()
print(response3)
// get me 5 documents from _id order00057 onwards
postAllDocsOptions1 := cloudantv1.PostAllDocsOptions{
Db: core.StringPtr("orders"),
StartKey: core.StringPtr("order00057"),
Limit: core.Int64Ptr(5),
}
allDocsResult1, response1, err := service.PostAllDocs(postAllDocsOptions1)
if err != nil {
panic(err)
}
b, _ := json.MarshalIndent(allDocsResult1, "", " ")
fmt.Println(string(b))
// get me 5 documents between _id order00057 --> order00077
postAllDocsOptions2 := cloudantv1.PostAllDocsOptions{
Db: core.StringPtr("orders"),
StartKey: core.StringPtr("order00057"),
EndKey: core.StringPtr("order00077"),
Limit: core.Int64Ptr(5),
}
allDocsResult2, response2, err := service.PostAllDocs(postAllDocsOptions2)
if err != nil {
panic(err)
}
b, _ := json.MarshalIndent(allDocsResult2, "", " ")
fmt.Println(string(b))
// get me 5 documents up to _id order00077
postAllDocsOptions3 := cloudantv1.PostAllDocsOptions{
Db: core.StringPtr("orders"),
EndKey: core.StringPtr("order00077"),
Limit: core.Int64Ptr(5),
}
allDocsResult3, response3, err := service.PostAllDocs(postAllDocsOptions3)
if err != nil {
panic(err)
}
b, _ := json.MarshalIndent(allDocsResult3, "", " ")
fmt.Println(string(b))
先前的 Go 示例需要以下导入块:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
"github.com/IBM/go-sdk-core/core"
)
所有 Go 示例都需要初始化 service
对象。 有关更多信息,请参阅 API 文档的 认证部分 以获取示例。
此实践意味着您定义数据集的大小以及要返回的 _id
字段的范围,但这与分页不同。
startkey
/endkey
值使用双引号,因为它们应该为 JSON 编码和 JSON.stringify('order00077') === "order00077"
。
分页选项
出于性能原因,如果要显示大量数据,那么必须考虑使用分页。 在这些示例中,将以 5 个块的形式访存文档。 但是,在实际应用程序中,页面大小可能不同,并取决于文档大小,等待时间需求,内存消耗和其他权衡。
您可以使用以下各节所述的选项。
选项 1-访存一个文档过多
访存 5 + 1 (limit=6
) 而不是访存五个文档 (limit=5
),但对用户隐藏第六个文档。 第六个文档的 _id
将成为下一页结果的请求的 startkey
。
请参阅下面的第一个请求示例:
curl -H "Authorization: Bearer $API_BEARER_TOKEN" "$SERVICE_URL/orders/_all_docs?limit=6"
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.AllDocsResult;
import com.ibm.cloud.cloudant.v1.model.DocsResultRow;
import com.ibm.cloud.cloudant.v1.model.PostAllDocsOptions;
Cloudant service = Cloudant.newInstance();
int pageSize = 5;
PostAllDocsOptions.Builder docsOptionsBuilder =
new PostAllDocsOptions.Builder()
.db("orders")
.limit(pageSize + 1); // Fetch pageSize + 1 documents
AllDocsResult response =
service.postAllDocs(docsOptionsBuilder.build())
.execute()
.getResult();
while (response.getRows().size() > 1) {
List<DocsResultRow> responseDocuments = response.getRows();
// on the last page, show all documents:
if (responseDocuments.size() <= pageSize) {
System.out.println(responseDocuments);
} else { // otherwise, hide the last document:
System.out.println(responseDocuments.subList(0, pageSize));
}
// The startKey of the next request becomes the hidden document id:
docsOptionsBuilder
.startKey(responseDocuments
.get(responseDocuments.size() - 1)
.getId()
);
response =
service.postAllDocs(docsOptionsBuilder.build())
.execute()
.getResult();
}
const { CloudantV1 } = require('@ibm-cloud/cloudant');
const service = CloudantV1.newInstance({});
async function paginate(pageSize) {
let allDocsResult = (await service.postAllDocs({
db: 'orders',
limit: pageSize + 1
})).result;
while(allDocsResult.rows.length > 1) {
let documents = allDocsResult.rows;
// on the last page, show all documents:
if(documents.length <= pageSize) {
console.log(documents);
} else { // otherwise, hide the last document:
console.log(documents.slice(0, documents.length - 1))
}
allDocsResult = (await service.postAllDocs({
db: 'orders',
limit: pageSize + 1,
startKey: documents[documents.length - 1].id
})).result;
}
}
paginate(5)
import json
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
page_size = 5
response = service.post_all_docs(
db='orders',
limit=page_size+1, # Fetch page_size + 1 documents
).get_result()
while len(response["rows"]) > 1:
documents = response['rows']
# on the last page, show all documents:
if len(documents) <= page_size:
print(json.dumps(documents, indent=2))
else: # otherwise, hide the last document:
print(json.dumps(documents[0:-1], indent=2))
response = service.post_all_docs(
db='orders',
limit=page_size+1, # Fetch page_size + 1 documents
start_key=documents[-1]['id']
).get_result()
pageSize := core.Int64Ptr(5)
postAllDocsOptions := service.NewPostAllDocsOptions(
"orders",
)
postAllDocsOptions.SetLimit(*pageSize + 1)
allDocsResult, _, err := service.PostAllDocs(postAllDocsOptions)
if err != nil {
panic(err)
}
for len(viewResult.Rows) > 1 {
documents := allDocsResult.Rows
// on the last page, show all documents:
if int64(len(documents)) <= *pageSize {
b, err := json.MarshalIndent(documents, "", " ")
if err != nil {
panic(err)
}
fmt.Printf(string(b))
} else { // otherwise, hide the last document:
b, err := json.MarshalIndent(documents[0:*pageSize], "", " ")
if err != nil {
panic(err)
}
fmt.Printf(string(b))
}
// The startKey of the next request becomes the hidden document id:
postAllDocsOptions.SetStartKey(*documents[len(documents)-1].ID)
allDocsResult, _, err = service.PostAllDocs(postAllDocsOptions)
if err != nil {
panic(err)
}
}
请看下面的第一个回复示例:
{
"total_rows": 11,
"offset": 0,
"rows": [
{ "id": "4eee973603bf77f30b1f880ed83df76a" ....},
{ "id": "4eee973603bf77f30b1f880ed83f469a" ....},
{ "id": "65fa623a384648740ec1f39b495d591c" ....},
{ "id": "d7404903579d6d5880514c22ad983529" ....},
{ "id": "example" ....},
{ "id": "mydoc" ....} // <-- This is the 6th result we use as the startkey of the next request
]
}
请参阅下面的第二个请求示例:
curl -H "Authorization: Bearer $API_BEARER_TOKEN" "$SERVICE_URL/orders/_all_docs?limit=6&startkey=\"mydoc\""
请参阅下面的第二个回复示例:
{
"total_rows": 11,
"offset": 5,
"rows": [
{ "id": "mydoc" ....},
{ "id": "order00057" ....},
...
]
}
先前的 Go 示例需要以下导入块:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
"github.com/IBM/go-sdk-core/core"
所有 Go 示例都需要初始化 service
对象。 有关更多信息,请参阅 API 文档的 认证部分 以获取示例。
此选项有效,但最终在仅需要 n
时访存 n+1
文档。
选项 2- \u0000 技巧
如果您决心每次只访存 n
个文档,那么需要计算值 startkey
,这意味着 the next ID after the last _id in the result set
。 例如,如果结果第一页中的最后一个文档是 "example",那么下一次调用 _all_docs
的 startkey
必须是什么? 它不能是“示例”,否则您将再次获取相同的文档标识。
结果是,您可以将 \u0000
附加到密钥字符串的末尾,以指示“下一个密钥”(\u0000
是 Unicode 空字符,可以按原样放置在 URL 中,也可以使用百分比代码 %00
)。 ).
请参阅下面的第一个请求示例:
curl -H "Authorization: Bearer $API_BEARER_TOKEN" "$SERVICE_URL/orders/_all_docs?limit=5"
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.AllDocsResult;
import com.ibm.cloud.cloudant.v1.model.DocsResultRow;
import com.ibm.cloud.cloudant.v1.model.PostAllDocsOptions;
Long pageSize = 5L;
PostAllDocsOptions.Builder docsOptionsBuilder =
new PostAllDocsOptions.Builder()
.db("orders")
.limit(pageSize); // Fetch pageSize documents
AllDocsResult response =
service.postAllDocs(docsOptionsBuilder.build())
.execute()
.getResult();
while (response.getRows().size() > 0) {
List<DocsResultRow> responseDocuments = response.getRows();
System.out.println(responseDocuments);
// The startKey of the next request becomes the last document id appended with `\u0000`
docsOptionsBuilder.startKey(
responseDocuments
.get(responseDocuments.size() - 1)
.getId() + '\u0000'
);
response =
service.postAllDocs(docsOptionsBuilder.build())
.execute()
.getResult();
}
const { CloudantV1 } = require('@ibm-cloud/cloudant');
const service = CloudantV1.newInstance({});
async function paginate(n) {
let allDocsResult = (await service.postAllDocs({
db: 'orders',
limit: n
})).result;
while (allDocsResult.rows.length > 0) {
let documents = allDocsResult.rows;
console.log(documents);
allDocsResult = (await service.postAllDocs({
db: 'orders',
limit: n,
startKey: documents[documents.length - 1].id + '\u0000'
})).result;
}
}
paginate(5)
import json
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
page_size = 5
response = service.post_all_docs(
db='orders',
limit=page_size,
).get_result()
while len(response["rows"]) > 0:
documents = response["rows"]
print(json.dumps(documents, indent=2))
response = service.post_all_docs(
db='orders',
limit=page_size+1, # Fetch page_size + 1 documents
start_key=documents[-1]["id"] + '\u0000'
).get_result()
pageSize := core.Int64Ptr(5)
postAllDocsOptions := service.NewPostAllDocsOptions(
"orders",
)
postAllDocsOptions.SetLimit(*pageSize)
allDocsResult, _, err := service.PostAllDocs(postAllDocsOptions)
if err != nil {
panic(err)
}
for len(allDocsResult.Rows) > 0 {
documents := allDocsResult.Rows
b, err := json.MarshalIndent(documents, "", " ")
if err != nil {
panic(err)
}
fmt.Printf(string(b))
// The startKeyDocId of the next request becomes the last document id appended with `\u0000`
postAllDocsOptions.SetStartKey(*documents[len(documents)-1].ID + "\u0000")
allDocsResult, _, err = service.PostAllDocs(postAllDocsOptions)
if err != nil {
panic(err)
}
}
请看下面的第一个回复示例:
{
"total_rows": 11,
"offset": 0,
"rows": [
{ "id": "4eee973603bf77f30b1f880ed83df76a" ....},
{ "id": "4eee973603bf77f30b1f880ed83f469a" ....},
{ "id": "65fa623a384648740ec1f39b495d591c" ....},
{ "id": "d7404903579d6d5880514c22ad983529" ....},
{ "id": "example" ....} // <-- append \u0000 to this to get the startkey of the next request
]
}
请参阅下面的第二个请求示例:
curl -H "Authorization: Bearer $API_BEARER_TOKEN" "$SERVICE_URL/orders/_all_docs?limit=5&startkey=\"example\u0000\""
请参阅下面的第二个回复示例:
{
"total_rows": 11,
"offset": 5,
"rows": [
{ "id": "mydoc" ....},
{ "id": "order00057" ....},
...
{ "id": "order00067" ....} <-- append \u0000 to this to get the startkey of the next request
]
}
先前的 Go 示例需要以下导入块:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
"github.com/IBM/go-sdk-core/core"
)
所有 Go 示例都需要初始化 service
对象。 有关更多信息,请参阅 API 文档的 认证部分 以获取示例。
视图分页
可以通过与 _all_docs
端点类似的方式查询 MapReduce 视图 (辅助索引),但改为使用 GET
或 POST
$SERVICE_URL/$DATABASE/_design/$DDOC/_view/$VIEW
端点。 MapReduce 视图由用户提供的 JavaScript 函数生成的 key-value
对定义。 您可以通过以下方式定义查询:
- 在没有参数的情况下假脱机视图中的所有数据。
- 通过提供
include_docs=true
来包含文档主体。 - 选择使用
startkey
/endkey
所需的键范围,但在这种情况下,键的数据类型可能不是字符串。
另一个复杂情况是,与每个 _id
都唯一的主索引不同,辅助索引可能具有具有相同键的条目。 例如,包含键 "herbivore"
的大量条目。 此情境通过仅使用 startkey
/endkey
棘手来进行分页,因此您可以使用其他参数来提供帮助: startkey_docid
/endkey_docid
。
请参阅下面的第一个请求示例:
# get first page of animals by diet
curl -H "Authorization: Bearer $API_BEARER_TOKEN" "$SERVICE_URL/animaldb/_design/views101/_view/diet?limit=3&startkey=\"herbivore\"&endkey=\"herbivore\""
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.PostViewOptions;
import com.ibm.cloud.cloudant.v1.model.ViewResult;
import com.ibm.cloud.cloudant.v1.model.ViewResultRow;
int pageSize = 3;
String diet = "herbivore";
PostViewOptions.Builder viewOptionsBuilder =
new PostViewOptions.Builder()
.db("animaldb")
.ddoc("views101")
.view("diet")
.limit(pageSize) // Fetch pageSize documents
.startKey(diet)
.endKey(diet);
ViewResult response =
service.postView(viewOptionsBuilder.build())
.execute()
.getResult();
while (response.getRows().size() > 0) {
List<ViewResultRow> responseDocuments = response.getRows();
System.out.println(responseDocuments);
// The startKeyDocId of the next request becomes the last document id appended with `\u0000`
viewOptionsBuilder.startKeyDocId(
responseDocuments
.get(responseDocuments.size() - 1)
.getId() + '\u0000'
);
response =
service.postView(viewOptionsBuilder.build())
.execute()
.getResult();
}
const { CloudantV1 } = require('@ibm-cloud/cloudant');
const service = CloudantV1.newInstance({});
async function paginate(pageSize) {
let diet = 'herbivore';
let requestParams = {
db: 'animaldb',
ddoc: 'views101',
view: 'diet',
limit: pageSize,
startKey: diet,
endKey: diet,
};
let viewResult = (await service.postView(requestParams)).result;
while (viewResult.rows.length > 0) {
let documents = viewResult.rows;
console.log(documents);
// The startKeyDocId of the next request becomes the last document id appended with `\u0000`
requestParams.startKeyDocId = documents[documents.length - 1].id + '\u0000';
viewResult = (await service.postView(requestParams)).result;
}
}
paginate(3)
import json
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
page_size = 3
diet = 'herbivore'
request_params = d = dict(
db='animaldb',
ddoc='views101',
view='diet',
limit=page_size,
start_key=diet,
end_key=diet,
)
response = service.post_view(**request_params).get_result()
while len(response["rows"]) > 0:
documents = response["rows"]
print(json.dumps(documents, indent=2))
# The startKeyDocId of the next request becomes the last document id appended with `\u0000`
request_params['start_key_doc_id'] = documents[-1]["id"] + '\u0000'
response = service.post_view(**request_params).get_result()
pageSize := core.Int64Ptr(5)
diet := "herbivore"
viewOptions := service.NewPostViewOptions(
"animaldb",
"views101",
"diet",
)
viewOptions.SetLimit(*pageSize)
viewOptions.SetStartKey(diet)
viewOptions.SetEndKey(diet)
viewResult, _, err := service.PostView(viewOptions)
if err != nil {
panic(err)
}
for len(viewResult.Rows) > 0 {
documents := viewResult.Rows
b, err := json.MarshalIndent(documents, "", " ")
if err != nil {
panic(err)
}
fmt.Printf(string(b))
// The startKeyDocId of the next request becomes the last document id appended with `\u0000`
viewOptions.SetStartKey(*documents[len(documents)-1].ID + "\u0000")
viewResult, _, err = service.PostView(viewOptions)
if err != nil {
panic(err)
}
}
请看下面的第一个回复示例:
{
"total_rows": 10,
"offset": 2,
"rows": [
{
"id": "elephant",
"key": "herbivore",
"value": 1
},
{
"id": "giraffe",
"key": "herbivore",
"value": 1
},
{
"id": "llama", // <-- append \u0000 to the startkey_docid to of the next request
"key": "herbivore",
"value": 1
}
]
}
请参阅下面的第二个请求示例:
# get next page of animals by diet
curl -H "Authorization: Bearer $API_BEARER_TOKEN" "$SERVICE_URL/animaldb/_design/views101/_view/diet?limit=3&startkey=\"herbivore\"&endkey=\"herbivore\"&startkey_docid=llama%00"
请参阅下面的第二个回复示例:
{
"total_rows": 10,
"offset": 5,
"rows": [
{
"id": "zebra",
"key": "herbivore",
"value": 1
}
]
}
先前的 Go 示例需要以下导入块:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
"github.com/IBM/go-sdk-core/core"
)
所有 Go 示例都需要初始化 service
对象。 有关更多信息,请参阅 API 文档的 认证部分 以获取示例。
换言之,第二个请求的值为 startkey_docid
,即上一页 results (llama) 中的最后一个文档标识加上 magic \u0000
字符 (在 URL 中变为 llama%00
)。
仅当提供了 startkey
并且所有索引条目共享一个键时,startkey_docid
参数才有效。 如果它们不共享密钥,那么只能通过处理 startkey
/endkey
参数来实现分页。 此外,startkey_docid
参数不是 JSON 编码的。
书签
假设您正在创建一个 Web 应用程序,该应用程序显示一组搜索结果,无论这些结果是书籍,参与者还是商店中的产品。 当用户滚动搜索结果时,将在末尾追加另一个匹配页面。 这种行为被称为“无限滚动”设计模式。 它允许用户轻松地无休止地滚动一个大数据集,而他们每次只从数据库中访存较小批次的数据。
IBM Cloudant 书签如何工作?
为其构建 IBM Cloudant 书签 的这种访问模式。 以下是其工作方式:
- 应用程序在 IBM Cloudant 数据库上运行搜索,例如
find me the first 10 cities where the country is "US"
。 - IBM Cloudant 提供了由 10 个 IBM Cloudant 文档和 书签组成的数组,这是一个不透明的键,用于表示指向结果集中下一个文档的指针。
- 当需要下一组结果时,将重复搜索。 但是,将查询与来自第一个响应的书签一起发送到请求中的 IBM Cloudant。
- IBM Cloudant 回复第二组文档和另一个书签,可用于获取第三页结果。
- 重复!
现在,您可以了解如何使用代码执行此操作。
如何使用 IBM Cloudant 查询进行搜索?
首先,搜索美国的所有城市。 您正在使用 IBM Cloudant 查询,因此操作指定为 JSON 块:
{
"selector": {
"$eq": {
"country": "US"
}
},
"limit": 5
}
通过使用 /db/_find
API 端点,结果将传递到 IBM Cloudant。
curl -X POST \
-H "Authorization: Bearer $API_BEARER_TOKEN" \
-H 'Content-type: application/json' \
-d '{"selector":{"country":{"$eq": "US"}},"limit":5}' \
"$SERVICE_URL/cities/_find"
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.FindResult;
import com.ibm.cloud.cloudant.v1.model.PostFindOptions;
import java.util.Collections;
import java.util.Map;
Cloudant service = Cloudant.newInstance();
Map<String, Object> selector = Collections.singletonMap(
"country",
Collections.singletonMap("$eq", "US"));
PostFindOptions.Builder findOptions = new PostFindOptions.Builder()
.db("cities")
.selector(selector)
.limit(5);
FindResult response = service.postFind(findOptions.build()).execute().getResult();
while (response.getDocs().size() > 0) {
System.out.println(response.getDocs());
// The bookmark of the next request becomes the bookmark of this response
findOptions.bookmark(response.getBookmark());
response = service.postFind(findOptions.build()).execute().getResult();
}
const { CloudantV1 } = require('@ibm-cloud/cloudant');
const service = CloudantV1.newInstance({});
async function paginate(pageSize) {
let requestParams = {
db: 'cities',
selector: {country: {'$eq': 'US'}},
limit: pageSize,
}
let findResult = (await service.postFind(requestParams)).result;
while (findResult.docs.length > 0) {
let documents = findResult.docs;
console.log(documents);
// The bookmark of the next request becomes the bookmark of this response
requestParams.bookmark = findResult.bookmark;
findResult = (await service.postFind(requestParams)).result;
}
}
paginate(5)
request_params = dict(
db='cities',
selector={'country': {'$eq': 'US'}},
limit=5,
)
response = service.post_find(**request_params).get_result()
while len(response['docs']) > 0:
documents = response['docs']
print(json.dumps(documents, indent=2))
# The bookmark of the next request becomes the bookmark of this response
request_params['bookmark'] = response['bookmark']
response = service.post_find(**request_params).get_result()
findOptions := service.NewPostFindOptions(
"cities",
map[string]interface{}{
"country": map[string]bool{
"$eq": "US",
},
},
)
findOptions.SetLimit(5)
findResult, _, err := service.PostFind(findOptions)
if err != nil {
panic(err)
}
for len(findResult.Docs) > 0 {
documents := findResult.Docs
b, err := json.MarshalIndent(documents, "", " ")
if err != nil {
panic(err)
}
fmt.Printf(string(b))
// The bookmark of the next request becomes the bookmark of this response
findOptions.Bookmark = findResult.Bookmark
findResult, _, err = service.PostFind(findOptions)
if err != nil {
panic(err)
}
}
先前的 Go 示例需要以下导入块:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
)
{
"docs":[
{"_id":"10104153","_rev":"1-32aab6258c65c5fc5af044a153f4b994","name":"Silver Lake","latitude":34.08668,"longitude":-118.27023,"country":"US","population":32890,"timezone":"America/Los_Angeles"},
{"_id":"10104154","_rev":"1-125f589bf4e39d8e119b4b7b5b18caf6","name":"Echo Park","latitude":34.07808,"longitude":-118.26066,"country":"US","population":43832,"timezone":"America/Los_Angeles"},
{"_id":"4046704","_rev":"1-2e4b7820872f108c077dab73614067da","name":"Fort Hunt","latitude":38.73289,"longitude":-77.05803,"country":"US","population":16045,"timezone":"America/New_York"},
{"_id":"4048023","_rev":"1-744baaba02218fd84b350e8982c0b783","name":"Bessemer","latitude":33.40178,"longitude":-86.95444,"country":"US","population":27456,"timezone":"America/Chicago"},
{"_id":"4048662","_rev":"1-e95c97013ece566b37583e451c1864ee","name":"Paducah","latitude":37.08339,"longitude":-88.60005,"country":"US","population":25024,"timezone":"America/Chicago"}
],
"bookmark": "g1AAAAA-eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqzmxiYWJiZGYGkOWDSyBJZAPCBD58"
}
响应包含 docs
和 bookmark
的数组,用于在下一个请求中对结果进行分页。 需要第 2 页结果时,通过从第一个响应传递 IBM Cloudant 书签来重复查询。
curl -X POST \
-H "Authorization: Bearer $API_BEARER_TOKEN" \
-H 'Content-type: application/json' \
-d '{"selector":{"country":{"$eq": "US"}},"limit":5,"bookmark":"g1AAAAA-eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqzmxiYWJiZGYGkOWDSyBJZAPCBD58"}' \
"$SERVICE_URL/cities/_find"
{
"docs":[
{"_id":"4049979","_rev":"1-1fa2591477c774a07c230571568aeb66","name":"Birmingham","latitude":33.52066,"longitude":-86.80249,"country":"US","population":212237,"timezone":"America/Chicago"},
{"_id":"4054378","_rev":"1-a750085697685e7bc0e49d103d2de59d","name":"Center Point","latitude":33.64566,"longitude":-86.6836,"country":"US","population":16921,"timezone":"America/Chicago"},
{"_id":"4058219","_rev":"1-9b4eb183c9cdf57c19be660ec600330c","name":"Daphne","latitude":30.60353,"longitude":-87.9036,"country":"US","population":21570,"timezone":"America/Chicago"},
{"_id":"4058553","_rev":"1-56100f7e7742028facfcc50ab6b07a04","name":"Decatur","latitude":34.60593,"longitude":-86.98334,"country":"US","population":55683,"timezone":"America/Chicago"},
{"_id":"4059102","_rev":"1-612ae37d982dc71eeecf332c1e1c16aa","name":"Dothan","latitude":31.22323,"longitude":-85.39049,"country":"US","population":65496,"timezone":"America/Chicago"}
],
"bookmark": "g1AAAAA-eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqzmxiYWhoaGIGkOWDSyBJZAO9qD40",
"warning": "no matching index found, create an index to optimize query time"
}
这一次,您将为下一个请求准备下一个五个城市和一个新书签。
IBM Cloudant 搜索如何工作?
对于 IBM Cloudant 搜索 查询,分页工作方式相同。 在 GET 请求的 URL 中或在 POST 请求的 JSON 主体中传递 bookmark
参数。 请参阅以下示例:
curl -H "Authorization: Bearer $API_BEARER_TOKEN" "$SERVICE_URL/cities/_search/search/_search/freetext?q=country:US&limit=5"
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.PostSearchOptions;
import com.ibm.cloud.cloudant.v1.model.SearchResult;
Cloudant service = Cloudant.newInstance();
PostSearchOptions.Builder searchOptions = new PostSearchOptions.Builder()
.db("cities")
.ddoc("search")
.index("freetext")
.query("country:US");
.limit(5);
SearchResult response = service.postSearch(searchOptions.build()).execute().getResult();
while (response.getRows().size() > 0) {
System.out.println(response.getRows());
// The bookmark of the next request becomes the bookmark of this response
searchOptions.bookmark(response.getBookmark());
response = service.postSearch(searchOptions.build()).execute().getResult();
}
const { CloudantV1 } = require('@ibm-cloud/cloudant');
async function paginate(pageSize) {
let requestParams = {
db: 'cities',
ddoc: 'search',
index: 'freetext',
query: 'country:US',
limit: 5
};
let searchResult = (await service.postSearch(requestParams)).result;
while (searchResult.rows.length > 0) {
let documents = searchResult.rows;
console.log(documents);
// The bookmark of the next request becomes the bookmark of this response
requestParams.bookmark = searchResult.bookmark;
searchResult = (await service.postSearch(requestParams)).result;
}
}
paginate(5);
selector = {'country': {'$eq': 'US'}}
request_params = dict(
db='cities',
ddoc='search',
index='freetext',
query='country:US',
limit=5,
)
response = service.post_search(**request_params).get_result()
while len(response['rows']) > 0:
documents = response['rows']
print(json.dumps(documents, indent=2))
# The bookmark of the next request becomes the bookmark of this response
request_params['bookmark'] = response['bookmark']
response = service.post_search(**request_params).get_result()
searchOptions := service.NewPostSearchOptions(
"cities",
"search",
"freetext",
"country:US"
)
searchOptions.SetLimit(5)
searchResult, _, err := service.PostSearch(searchOptions)
if err != nil {
panic(err)
}
for len(searchResult.Rows) > 0 {
documents := searchResult.Rows
b, err := json.MarshalIndent(documents, "", " ")
if err != nil {
panic(err)
}
fmt.Printf(string(b))
// The bookmark of the next request becomes the bookmark of this response
searchOptions.Bookmark = searchResult.Bookmark
searchResult, _, err = service.PostSearch(searchOptions)
if err != nil {
panic(err)
}
}
先前的 Go 示例需要以下导入块:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
)
{
"total_rows": 65,
"rows":[
{"_id":"10104153","_rev":"1-32aab6258c65c5fc5af044a153f4b994","name":"Silver Lake","latitude":34.08668,"longitude":-118.27023,"country":"US","population":32890,"timezone":"America/Los_Angeles"},
{"_id":"10104154","_rev":"1-125f589bf4e39d8e119b4b7b5b18caf6","name":"Echo Park","latitude":34.07808,"longitude":-118.26066,"country":"US","population":43832,"timezone":"America/Los_Angeles"},
{"_id":"4046704","_rev":"1-2e4b7820872f108c077dab73614067da","name":"Fort Hunt","latitude":38.73289,"longitude":-77.05803,"country":"US","population":16045,"timezone":"America/New_York"},
{"_id":"4048023","_rev":"1-744baaba02218fd84b350e8982c0b783","name":"Bessemer","latitude":33.40178,"longitude":-86.95444,"country":"US","population":27456,"timezone":"America/Chicago"},
{"_id":"4048662","_rev":"1-e95c97013ece566b37583e451c1864ee","name":"Paducah","latitude":37.08339,"longitude":-88.60005,"country":"US","population":25024,"timezone":"America/Chicago"}
],
"bookmark": "g1AAAAA-eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqzmxiYWJiZGYGkOWDSyBJZAPCBD58"
}
您可以使用 bookmark
请求参数来准备前五个城市和书签以用于下一个请求。
curl -H "Authorization: Bearer $API_BEARER_TOKEN" "$SERVICE_URL/cities/_search/search/_search/freetext?q=country:US&limit=5&bookmark=g1AAAAA-eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqzmxiYWJiZGYGkOWDSyBJZAPCBD58"
{
"total_rows": 65,
"rows":[
{"_id":"4049979","_rev":"1-1fa2591477c774a07c230571568aeb66","name":"Birmingham","latitude":33.52066,"longitude":-86.80249,"country":"US","population":212237,"timezone":"America/Chicago"},
{"_id":"4054378","_rev":"1-a750085697685e7bc0e49d103d2de59d","name":"Center Point","latitude":33.64566,"longitude":-86.6836,"country":"US","population":16921,"timezone":"America/Chicago"},
{"_id":"4058219","_rev":"1-9b4eb183c9cdf57c19be660ec600330c","name":"Daphne","latitude":30.60353,"longitude":-87.9036,"country":"US","population":21570,"timezone":"America/Chicago"},
{"_id":"4058553","_rev":"1-56100f7e7742028facfcc50ab6b07a04","name":"Decatur","latitude":34.60593,"longitude":-86.98334,"country":"US","population":55683,"timezone":"America/Chicago"},
{"_id":"4059102","_rev":"1-612ae37d982dc71eeecf332c1e1c16aa","name":"Dothan","latitude":31.22323,"longitude":-85.39049,"country":"US","population":65496,"timezone":"America/Chicago"}
],
"bookmark": "g1AAAAA-eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqzmxiYWhoaGIGkOWDSyBJZAO9qD40",
}
请参阅有关 查询参数 的文档以获取更多详细信息。
MapReduce 视图是否接受书签?
编号 MapReduce 视图不接受 bookmark
。 请改为使用下列其中一个技巧来浏览结果:
我可以直接跳到第 X 页的结果吗?
编号 如果书签来自上一页结果,那么仅对 IBM Cloudant 有意义。 如果需要结果的页面 3,那么必须先访存页面 1 和 2。
如果我提供了不正确的书签,会发生什么情况?
如果提供了无效书签,那么 IBM Cloudant 将通过 HTTP 400 Bad Request { error: 'invalid_bookmark'}
响应进行响应。 请记住,对于序列中的第一个搜索,您不需要书签。
如果我更改查询会发生什么?
您必须保留相同的查询 ( IBM Cloudant 查询中的相同选择器或 IBM Cloudant 搜索中的相同 "q") 以获取下一页结果。 如果更改查询,那么您可能会在应答中获取空的结果集。