在本系列文章的第三部分,将深入探讨PouchDB数据库的查询功能。PouchDB是一个NoSQL数据库,它允许在不依赖服务器的情况下存储和查询数据。在前两篇文章中,已经学会了如何创建数据库、修改文档以及使用allDocs()
方法检索文档。现在,将学习如何使用find()
插件来基于文档中的任何属性进行查询。
pouchdb-find
插件可以在GitHub上下载。find()
方法,也称为Mango查询,是一种结构化查询机制,允许在创建的二级索引上执行搜索。这种方法对于回答诸如“查找所有lastName为'sheriff'的文档”或“查找所有cost大于75的文档”这样的问题非常有用。需要下载pouchdb.find
插件,并在HTML文件中添加对pouchdb-find.js
文件的链接。
虽然不必在想查询的字段上创建索引,但如果不这样做,就会对所有文档进行完整的扫描。这取决于数据库中有多少文档,这可能是一个相当昂贵(且慢)的操作。如果知道最常查询的字段,就在这些字段上创建一个或多个索引。下面的代码示例展示了如何在lastName
属性和cost
属性上创建索引。
function createIndexes() {
// 在lastName上创建索引
db.createIndex({
index: {
fields: ['lastName']
}
}).then(function(response) {
pouchDBSamplesCommon.displayJSON(response);
}).catch(function(err) {
pouchDBSamplesCommon.displayMessage(err);
});
// 在cost上创建索引
db.createIndex({
index: {
fields: ['cost']
}
}).then(function(response) {
pouchDBSamplesCommon.displayJSON(response);
}).catch(function(err) {
pouchDBSamplesCommon.displayMessage(err);
});
}
如果尝试在没有索引的字段上进行排序,将会收到PouchDB的错误。如果在selector
中使用的字段没有索引,那么默认索引(即_id
字段)将被使用,并且将执行完整的文档扫描。PouchDB没有能力在没有该字段索引的情况下对数据进行排序,因此,会收到错误。
function showError() {
// 注意:在排序字段上创建索引,否则会出错
db.find({
selector: { firstName: 'Paul' },
sort: ['firstName']
}).then(function(response) {
pouchDBSamplesCommon.displayJSON(response);
}).catch(function(err) {
pouchDBSamplesCommon.displayMessage(err);
});
}
如果在selector
中使用了字段,但没有可用的索引,将在数据库中执行完整的文档扫描。数据将返回适当的文档选择,但会收到一个警告,表明没有找到匹配的索引。然后,可以决定是否创建一个。
function showWarning() {
// 注意:如果在'selector'中使用了未索引的属性名称,会收到一个错误
db.find({
selector: { firstName: 'Paul' }
}).then(function(response) {
pouchDBSamplesCommon.displayJSON(response);
}).catch(function(err) {
pouchDBSamplesCommon.displayMessage(err);
});
}
之前在lastName
字段上创建了一个索引。现在可以通过在selector
属性中指定lastName
来使用该索引。可以通过包括fields
属性来进一步限定返回的内容。这个属性是一个数组,包含了希望从这个查询中返回的文档中的属性名称。可以包括sort
属性,但这实际上是不必要的。当使用索引时,文档将按索引顺序返回。
function findLastName() {
db.find({
selector: { lastName: 'Sheriff' },
fields: ['_id', 'firstName', 'lastName'],
sort: ['lastName']
}).then(function(response) {
pouchDBSamplesCommon.displayJSON(response);
}).catch(function(err) {
pouchDBSamplesCommon.displayMessage(err);
});
}
可以使用许多选择器操作符,而不仅仅是搜索完全匹配。选择器操作符以美元符号为前缀,包括:$eq
、$gt
、$gte
、$lt
、$lte
、$in
。创建一个使用$in
操作符的函数,以定位文档中的多个姓氏。下面的代码显示了搜索姓氏为'Sheriff'或'Jones'的文档。
function findLastNames() {
pouchDBSamplesCommon.hideMessageAreas();
db.find({
selector: {
lastName: { $in: ['Sheriff', 'Jones'] }
},
fields: ['_id', 'firstName', 'lastName']
}).then(function(response) {
pouchDBSamplesCommon.displayJSON(response);
}).catch(function(err) {
pouchDBSamplesCommon.displayMessage(err);
});
}
另一个有用的选择器操作符是大于($gt
)。之前在文档的cost
属性上创建了一个索引,这些文档的docType
为'service'。使用以下代码查找所有cost大于75的服务:
function greaterThan() {
pouchDBSamplesCommon.hideMessageAreas();
db.find({
selector: { cost: { $gt: 75 } },
fields: ['_id', 'cost']
}).then(function(response) {
pouchDBSamplesCommon.displayJSON(response);
}).catch(function(err) {
pouchDBSamplesCommon.displayMessage(err);
});
}
function searchTwoFields() {
// 在两个字段上创建索引
db.createIndex({
index: {
fields: ['docType', 'cost']
}
}).then(function(response) {
// 在两个字段上搜索
return db.find({
selector: {
docType: 'service',
cost: { $gt: 75 }
},
fields: ['_id', 'cost']
});
}).then(function(response) {
pouchDBSamplesCommon.displayJSON(response);
}).catch(function(err) {
pouchDBSamplesCommon.displayMessage(err);
});
}