PouchDB简单入门

PouchDB是一款数据库。它可以在浏览器里面存储你的本地信息,所以适合于基于浏览器的可离线存储方案。PouchDB实际上是一个JavaScript库。

快速入门

可以参考Getting Started Guide入门PouchDB。

安装PouchDB与使用

安装:`npm install pouchdb --save`

使用:`var PouchDB = require('pouchdb');`

简单操作

新增与修改数据

db.put({},function callback(err,result){})。新的数据中每一条都要有一个唯一的主键_id,在提交的数据里,如果存在与数据库中相同的_id,PouchDB就将更新该数据,否者就创建一条新数据。使用db.post可以提交没有_id的数据。回调函数callback中:如果err为非空,说明插入数据失败;如果err为空,则表示插入成功,result里返回成功后数据_id_rev_rev代表这条数据的版本号。

删除数据

db.remove()。删除数据的时候,我们需要同时提供_id_rev项。我们使用remove()的时候,并没有真正删除掉文档,它只是被添加了一个_deleted标志,值为true。以下3种写法都可以删除数据:

db.get('mittens').then(function (doc) {
  return db.remove(doc);
});

db.get('mydoc').then(function (doc) {
  return db.remove(doc._id, doc._rev);
});

db.get('mydoc').then(function (doc) {
  doc._deleted = true;
  return db.put(doc);
});

查询数据

db.get(_id)获得指定的数据

在浏览器中查看PouchDB

通过PouchDB Inspector,它是用于在Chrome中查看PouchDB的插件。

通过浏览器中的IndexedDB/WebSQL查看。

debug模式

开启debug模式:PouchDB.debug.enable('*')
关闭debug模式:PouchDB.debug.disable()

删除本地数据库

在Chrome中,通过使用ClearBrowserData extension插件删除

在Firefox中,通过使用Clear Recent History+ add-on插件删除

在Safari中,通过 Safari → Clear History and Website Data 删除

通过代码:db.destroy(),返回的是一个Promise

理解revisions(_rev)

字段_rev是一个版本标志。它是在新增或者修改的时候生成的一个随机数。在PouchDB中,更新数据的时候必须要有_rev字段作为条件。如:

var doc = {
  '_id': 'mittens',
  '_rev': '1-7df5244f3d6cf5d5b260b9c641f9c604',
  'name': 'Mittens',
  'occupation': 'kitten',
  'age': 4,
  'hobbies': [
    'playing with balls of yarn',
    'chasing laser pointers',
    "lookin' hella cute"
  ]
}

如果没有_rev字段,更新的时候就会报错。

{
    status: 409,
    name: 'conflict',
    message: 'Documentupdateconflict',
    error: true
}

为什么我们一定需要_rev呢?因为使用_rev可以更好地进行同步工作

Asynchronous Code

PouchDB提供了一个完全异步API。

callback形式:

db.get('mittens', function (error, doc) {
  if (error) {
    // oh noes! we got an error
  } else {
    // okay, doc contains our document
  }
});

Promise形式:

db.get('mittens').then(function (doc) {
  // okay, doc contains our document
}).catch(function (err) {
  // oh noes! we got an error
});

批量操作

可以使用bulkDocs()和allDocs()进行批量操作

使用bulkDocs()一次性操作多个doc

db.bulkDocs([
  {
    _id: 'mittens',
    occupation: 'kitten',
    cuteness: 9.0
  },
  {
    _id: 'katie',
    occupation: 'kitten',
    cuteness: 7.0
  },
  {
    _id: 'felix',
    occupation: 'kitten',
    cuteness: 8.0
  }
])

使用bulkDocs()可以在一次请求中进行处理操作。我们也可以使用bulkDocs()批量修改或者批量删除,每个对象中都包含_rev_deleted即可。

因为PouchDB并不支持事务。所以在bulkDocs()中,一个操作失败了,并不能确保所有的操作都失败。

使用allDocs()一次性读取多个doc

我们使用allDocs()返回的数据是按照_id排序的。

db.allDocs({include_docs: true}).then(res => {
    console.log(JSON.stringify(res))
})

如果我们没有传入include_docs: true只会返回基本的id、key和value.rev。

在allDocs()中,你可以进行排序、过滤等操作。可以通过阅读“Pagination strategies with PouchDB”获悉如何进行分页操作。

附件操作

PouchDB支持附件操作

如何存储附件

可以使用base64-encoded格式或者Blob进行存储附件。

存储一个附件:

db.put({
  _id: 'mydoc',
  _attachments: {
    'myattachment.txt': {
      content_type: 'text/plain',
      data: 'aGVsbG8gd29ybGQ='
    }
  }
})

以上代码中,myattachment.txt是文件名;content_type是格式;aGVsbG8gd29ybGQ=是base64编码后的数据。

我们如何读取附件呢?

db.get('mydoc').then(data => {
    console.log(data)
})

使用以上代码时,PouchDB只会附件的基本信息,返回:

{
    _attachments: {
        myattachment.txt: {
            content_type: "text/plain",
            digest: "md5-XrY7u+Ae7tCTyyK7j1rNww==",
            length: 11,
            revpos: 1,
            stub: true
        }
    },
    _id: "mydoc",
    _rev: "1-a2308e4759440419de42048838ed86d3"
}

要获得附件内容,我们必须得在查询中添加参数:attachments: true

db.get('mydoc', {attachments: true}).then(data => {
    console.log(data)
})

图片附件

db.put({
    _id: 'meowth',
    _attachments: {
      'meowth.png': {
        content_type: 'image/png',
        data: 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAkCAIAAAB0Xu9BAAAABGdBTUEAALGPC/xhBQAAAuNJREFUWEetmD1WHDEQhDdxRMYlnBFyBIccgdQhKVcgJeQMpE5JSTd2uqnvIGpVUqmm9TPrffD0eLMzUn+qVnXPwiFd/PP6eLh47v7EaazbmxsOxjhTT88z9hV7GoNF1cUCvN7TTPv/gf/+uQPm862MWTL6fff4HfDx4S79/oVAlAUwqOmYR0rnazuFnhfOy/ErMKkcBFOr1vOjUi2MFn4nuMil6OPh5eGANLhW3y6u3aH7ijEDCxgCvzFmimvc95TekZLyMSeJC68Bkw0kqUy1K87FlpGZqsGFCyqEtQNDdFUtFctTiuhnPKNysid/WFEFLE2O102XJdEE+8IgeuGsjeJyGHm/xHvQ3JtKVsGGp85g9rK6xMHtvHO9+WACYjk5vkVM6XQ6OZubCJvTfPicYPeHO2AKFl5NuF5UK1VDUbeLxh2BcRGKTQE3irHm3+vPj6cfCod50Eqv5QxtwBQUGhZhbrGVuRia1B4MNp6edwBxld2sl1splfHCwfsvCZfrCQyWmX10djjOlWJSSy3VQlS6LmfrgNvaieRWx1LZ6s9co+P0DLsy3OdLU3lWRclQsVcHJBcUQ0k9/WVVrmpRzYQzpgAdQcAXxZzUnFX3proannrYH+Vq6KkLi+UkarH09mC8YPr2RMWOlEqFkQClsykGEv7CqCUbXcG8+SaGvJ4a8d4y6epND+pEhxoN0vWUu5ntXlFb5/JT7JfJJqoTdy9u9qc7ax3xJRHqJLADWEl23cFWl4K9fvoaCJ2BHpmJ3s3z+O0U/DmzdMjB9alWZtg4e3yxzPa7lUR7nkvxLHO9+tvJX3mtSDpwX8GajB283I8R8a7D2MhUZr1iNWdny256yYLd52DwRYBtRMvE7rsmtxIUE+zLKQCDO4jlxB6CZ8M17GhuY+XTE8vNhQiIiSE82ZsGwk1pht4ZSpT0YVpon6EvevOXXH8JxVR78QzNuamupW/7UB7wO/+7sG5V4ekXb4cL5Lyv+4IAAAAASUVORK5CYII='
      }
    }
  }).then(function () {
    return db.getAttachment('meowth', 'meowth.png')
  }).then(function (blob) {
    var url = URL.createObjectURL(blob)
    var img = document.createElement('img')
    img.src = url
    document.body.appendChild(img)
  }).catch(function (err) {
    console.log(err)
  })

上面代码中,我们使用URL.createObjectURL(),将Blob转换成URL。

上面代码更值得让我们注意的是,使用了db.getAttachment方法。该方法返回一个Blob,而不是返回base64编码的String。不过我们可以在base64和blob直接互转。

直接存储二进制数据

可以直接使用putAttachment()方法,如果已经存在附件则该方法将覆盖已存在的附件,如果不存在附件则创建一个新的附件。

在NodeJS中,PouchDB返回的Blobs被Buffers代替。同样的,在PouchDB中,NodeJS的Buffers被Blobs替代。

附件上传

可以使用H5的FileAPI上传附件,也可以使用<input type="file">进行附件上传,而且它们的元素已经是Blob。以下是一个简单的例子:

<input type="file">

var input = document.querySelector('input');
input.addEventListener('change', function () {
  var file = input.files[0]; // file is a Blob

  db.put({
    _id: 'mydoc',
    _attachments: {
      filename: {
        type: file.type,
        data: file
      }
    }
  }).catch(function (err) {
    console.log(err);
  });
});

Base64 vs Blobs/Buffers

PouchDB将根据Base64格式的数据或者Blobs/Buffers数据选择最佳的存储结构。

根据官方例子的代码,我们可以在使用put()保存Blobs,也可以使用putAttachment()保存Base64。getAttachment()方法总是返回Blobs。在各个查询方法中,都可以传入选项{attachments: true},返回Base64;传入参数{binary: true}返回二进制。