65.9K
CodeProject 正在变化。 阅读更多。
Home

开始使用 PouchDB - 第 3 部分

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2019 年 1 月 21 日

CPOL

4分钟阅读

viewsIcon

8666

downloadIcon

62

在本系列文章的第三篇中,您将学习如何在 PouchDB 数据库中查询数据。

引言

在 CodeProject.com 上的前两篇文章中,您已经了解了 PouchDB NoSQL 数据库。

在这两篇文章中,您学会了创建新数据库、修改数据库中的文档以及使用 allDocs() 检索文档。现在您已经向 PouchDB 数据库插入了几份文档,您可能希望根据 _id 属性以外字段中的数据来检索文档。在我们关于 PouchDB 的系列文章的第三部分中,您将学习使用 find() 插件对文档中的任何属性执行查询。

Mango 查询

pouchdb-find 插件可在 GitHub 上下载。find() 方法,也称为 Mango,是一种结构化查询机制,允许您创建用于执行搜索的二级索引。此方法对于回答以下问题非常有用:查找 lastName 等于 'sheriff' 的所有文档,或 cost 大于 75 的文档。下载 pouchdb.find 插件并将链接添加到 pouchdb-find.js 文件。此链接应放在 pouchdb-xxxxx.js 文件链接之后。

<script src="../Scripts/pouchdb-6.4.3.min.js"></script>
<script src="../Scripts/pouchdb.find.js"></script>

创建索引

您不必对要查询的字段创建索引,但如果不创建,则会扫描所有文档。根据数据库中文档的数量,这可能是一项非常昂贵(且缓慢)的操作。如果您知道最常查询的字段,请在这些字段上创建索引。下面的代码示例说明了如何为 lastName 属性创建索引,并为 cost 属性创建另一个索引。

function createIndexes() {
  // Create index on last Name
  db.createIndex({
    index: {
      fields: ['lastName']
    }
  }).then(function (response) {
    pouchDBSamplesCommon.displayJSON(response);
  }).catch(function (err) {
    pouchDBSamplesCommon.displayMessage(err);
  });

  // Create index on cost
  db.createIndex({
    index: {
      fields: ['cost']
    }
  }).then(function (response) {
    pouchDBSamplesCommon.displayJSON(response);
  }).catch(function (err) {
    pouchDBSamplesCommon.displayMessage(err);
  });
}

请注意,fields 属性是属性名称的数组。您可以指定一组要索引的字段。例如,您可能希望首先按 lastName 字段索引,然后按 firstName 字段索引。

无索引时排序错误

如果您尝试对未索引的字段进行排序,您将收到 PouchDB 的错误。如果 selector 中使用的字段没有索引,则使用默认索引(_id 字段),并执行完整文档扫描。PouchDB 无法在字段没有索引的情况下排序数据,因此您会收到错误。

function showError() {
  // NOTE: Create an index on the sort field or you get an error
  db.find({
    selector: { firstName: 'Paul' },
    sort: ['firstName']
  }).then(function (response) {
    pouchDBSamplesCommon.displayJSON(response);
  }).catch(function (err) {
    pouchDBSamplesCommon.displayMessage(err);
  });
}

运行上述函数时收到的错误消息是

Error: Cannot sort on field(s) "firstName" when using the default index

无索引时警告

如果您在选择器中使用字段且没有可用的索引,则会在数据库中执行完整的文档扫描。数据将返回带有适当选定文档的结果,但您会收到一条警告,提示未找到匹配的索引。然后,您可以决定是否要创建一个。

function showWarning() {
// NOTE: You get an error if you use a property name in the 'selector' that is not indexed
  db.find({
    selector: { firstName: 'Paul' }
  }).then(function (response) {
    pouchDBSamplesCommon.displayJSON(response);
  }).catch(function (err) {
    pouchDBSamplesCommon.displayMessage(err);
  });
}

收到的响应对象如下所示

{
  "docs": [
    {
      "firstName": "Paul",
      "lastName": "Sheriff",
      "docType": "technician",
      "_id": "psheriff",
      "_rev": "1-36a6815e79f54819bc0b4ee3bd435aa1"
    }
  ],
  "warning": "no matching index found, create an index to optimize query time"
}

查找姓氏

您之前已在 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);
  });
}

上述查询的结果如下所示

{
  "docs": [
    {
      "_id": "msheriff",
      "firstName": "Madison",
      "lastName": "Sheriff"
    },
    {
      "_id": "psheriff",
      "firstName": "Paul",
      "lastName": "Sheriff"
    }
  ]
}

查找多个姓氏

除了精确匹配搜索之外,您还可以使用许多选择器运算符。选择器运算符以美元符号 ($) 为前缀,包括:$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);
  });
}

上面查询的返回结果如下所示。请注意,此选择器运算符不使用基于姓氏字段的索引。某些类型的运算符并非总是能够使用索引;$in$or$regex 是其中一些不能使用的。

{
  "docs": [
    {
      "_id": "bjones",
      "firstName": "Bruce",
      "lastName": "Jones"
    },
    {
      "_id": "msheriff",
      "firstName": "Madison",
      "lastName": "Sheriff"
    },
    {
      "_id": "psheriff",
      "firstName": "Paul",
      "lastName": "Sheriff"
    }
  ],
  "warning": "no matching index found, create an index to optimize query time"
}

查找成本大于 75

另一个有用的选择器运算符是大于 ($gt)。您之前已在 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);
  });
}

搜索两个字段

您不限于只为单个字段建立索引。您可以在索引的 fields 属性中包含两个或多个字段。在 selector 属性中,您现在可以指定两个要匹配的字段。在下面的示例代码中,您正在查询文档,查找 doctype 等于 'service' 且 cost 大于 75 的文档。

function searchTwoFields() {
  // Create index on two fields
  db.createIndex({
    index: {
      fields: ['docType', 'cost']
    }
  }).then(function (response) {
    // Search on two fields
    return db.find({
      selector: {
        docType: 'service',
        cost: { $gt: 75 }
      },
      fields: ['_id', 'cost']
    });
  }).then(function (response) {
    pouchDBSamplesCommon.displayJSON(response);
  }).catch(function (err) {
    pouchDBSamplesCommon.displayMessage(err);
  });
}

摘要

在本系列关于 PouchDB 的第三部分中,您学习了如何使用 find() 方法。此方法是 PouchDB 的一个插件,因此您必须单独下载它。find() 方法允许您搜索文档中 _id 字段以外的字段。请务必为要搜索的字段创建索引,因为这样做可以提高搜索性能。在下一篇文章中,您将学习如何使用 query() 方法和 map 函数。

© . All rights reserved.