Sebastian Seitz和Taulant Spahiu对此文章进行了同行评审。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!
近年来,客户端Web应用程序变得越来越复杂。 浏览器一直以来都提供更好的JavaScript性能,并且能够使用丰富的JavaScript API(例如地理定位和点对点通信)来做越来越多的事情。
富Web应用程序的兴起也带来了对良好的客户端存储机制的需求,这就是JavaScript数据库(如PouchDB)应运而生的地方。
什么是PouchDB?
PouchDB是一个受Apache CouchDB启发的开源JavaScript数据库,旨在在浏览器中良好运行。
什么是JavaScript数据库?
简单来说,JavaScript数据库是一个JavaScript对象,它提供用于放置,获取和搜索数据的方法(或API)。 实际上,一个普通的旧JavaScript对象是最简单的JavaScript数据库。 如果您熟悉Meteor ,那么您可能听说过Minimongo ,它是另一个模仿MongoDB API的客户端JavaScript数据库。
PouchDB是CouchDB的JavaScript实现。 它的目标是在浏览器或Node.js中运行时,以接近完美的保真度模拟CouchDB API。
PouchDB与Minimongo这样的数据库的不同之处在于,默认情况下,它不仅是内存中的,它还在后台使用IndexedDB进行存储。 IndexedDB是用于客户端存储大量结构化数据(包括文件/ blob)的低级API。 这意味着PouchDB数据存储在磁盘上,并且即使在页面刷新后仍然可用(但是,一个浏览器存储的数据将对其他浏览器不可用)。
不同的适配器使您可以更改基础数据存储层。
与CouchDB的关系
PouchDB是CouchDB的JavaScript实现,并尽可能接近其API。
在CouchDB中,您将使用此API调用获取所有文档
/db/_all_docs?include_docs=true
在PouchDB中,它变成
db.allDocs({include_docs: true})
PouchDB使应用程序可以在脱机时在本地存储数据,然后在应用程序恢复在线时将其与CouchDB同步。
现在,让我们看看如何在应用程序中使用PouchDB。
安装
要开始使用PouchDB,您只需要包括PouchDB客户端库。 您可以使用独立的构建,这使PouchDB
构造函数在window
对象上全局可用
<script src="https://cdn.jsdelivr.net/pouchdb/5.4.5/pouchdb.min.js"></script>
或者,如果您在Node.js / browserify / webpack环境中使用它,则可以使用npm
进行安装。
$ npm install pouchdb --save
然后在您的JavaScript中:
var PouchDB = require('pouchdb');
(有趣的事实: npm isntall pouchdb
也可以使用!)
使用PouchDB
建立资料库
创建PouchDB数据库就像调用PouchDB构造函数一样简单。 让我们创建一个名为“电影”的数据库。
var movies = new PouchDB('Movies');
运行之后,您可以使用info
方法查看有关数据库的基本信息,该方法返回Promise
。
movies
.info()
.then(function (info) {
console.log(info);
})
上面的代码输出以下内容:
{"doc_count":0,"update_seq":0,"idb_attachment_format":"binary","db_name":"Movies","auto_compaction":false,"adapter":"idb"}
adapter
字段指示其下方正在使用IndexedDB。
处理文件
PouchDB是基于文档的NoSQL数据库,因此没有严格的架构,您可以直接插入JSON文档。 让我们看看如何插入,更新,检索或删除文档。
建立文件
您可以使用put
方法创建一个新文档
// returns a promise
db.put(doc, [docId], [docRev], [options])
方括号中的参数是可选的。 每个文档都有一个与它关联的_id
字段,它用作唯一标识符。
通过运行以下代码,在以前创建的Movies
数据库中创建一个新文档:
movies
.put({
_id: 'tdkr',
title: 'The Dark Knight Rises',
director: 'Christopher Nolan'
}).then(function (response) {
console.log("Success", response)
}).then(function (err) {
console.log("Error", err)
})
在成功的情况下,响应将类似于:
Success {ok: true, id: "tdkr", rev: "3-f8afdea539618c3e8dceb20ba1659d2b"}
现在调用movies.info()
将给出{doc_count: 1}
以及其他数据,表明我们的文档确实已插入。
响应中的rev
字段指示文档的修订。 每个文档都有一个名为_rev
的字段。 每次更新文档时,文档的_rev
字段都会更改。 每个修订版均指向其先前的修订版。 PouchDB维护每个文档的历史记录(类似于git)。
阅读文件
PouchDB提供了一种get
API方法,用于通过其ID检索文档。 运行:
movies
.get('tdkr')
.then(function(doc) {
console.log(doc)
})
.catch(function (err) {
console.log(err)
})
会给像
{title: "The Dark Knight Rises", director: "Christopher Nolan", _id: "tdkr", _rev: "3-f8afdea539618c3e8dceb20ba1659d2b"}
更新文件
假设我们要在文档中添加一个“年份”字段。 您可以通过运行以下命令来更新上面创建的文档:
movies
.get('tdkr')
.then(function(doc) {
doc.year = "2012" // new field
console.log(doc._rev) // doc has a '_rev' field
return db.put(doc) // put updated doc, will create new revision
}).then(function (res) {
console.log(res)
})
更新文档时,必须提供_rev
字段。
您应该在控制台中看到类似的输出:
{ok: true, id: "tdkr", rev: "4-7a34189fb8f2e28fe08b666e699755b8"}
指示文档的新修订版。
删除文件
在PouchDB中删除文档只是将其_deleted
属性设置为true
。 您可以调用.remove()
来做到这一点:
movies
.get('tdkr')
.then(function(doc) {
return movies.remove(doc) // return the promise
}).then(function(res) {
console.log("Remove operation response", res)
})
等同于做
movies
.get('tdkr')
.then(function (doc) {
doc._deleted = true
return db.put(doc)
})
.then(...)
删除数据库
您可以通过在db对象上调用destroy()
来删除数据库。
// returns a promise
movies.destroy()
批量操作
到目前为止,我们一直使用PouchDB中的单个文档。 但是,它还提供了用于处理文档集合的API。 PouchDB提供了两种用于批量操作的方法bulkDocs()
用于批量写入,以及allDocs()
用于批量读取。
bulkDocs()
方法非常简单。 它只需要将一系列文档插入数据库。
插入多个文件
// Returns a promise
movies.bulkDocs([
{
_id: 'easy-a',
title: "Easy A",
// other attribues
},
{
_id: 'black-swan',
title: 'Black Swan',
// ...
}
])
样本响应:
[
{
"ok": true,
"id": "easy-a",
"rev": "1-84abc2a942007bee7cf55007cba56198"
},
{
"ok": true,
"id": "black-swan",
"rev": "1-7b80fc50b6af7a905f368670429a757e"
}
]
如果要插入多个文档,则使用批量API通常比执行多个put()
请求更好。 批量操作往往比单个操作要快,因为它们可以组合为单个事务(对于本地IndexedDB / WebSQL存储)或单个HTTP请求(对于远程CouchDB服务器)。
检索多个文件
要阅读多个文档,PouchDB提供了allDocs()
方法。
// without {include_docs: true}, only document ids are returned
movies
.allDocs({include_docs: true})
.then(function (docs) {
console.log(docs)
})
这是一种快速且非常有用的方法。 从PouchDB文档中:
allDocs()是PouchDB世界的无名小卒。 它不仅可以按顺序返回文档,还可以颠倒顺序,使用_id进行过滤,使用_id上的“大于”和“小于”操作对切片和切成小方块,等等。
默认情况下,文档以_id
升序返回。 您可以指定{descending: true}
以颠倒顺序。
movies
.allDocs({
include_docs: true,
descending: true
})
.then(...)
您还可以指定startkey
和endkey
参数以获取一定范围内的文档。 例如,要获取所有_id
以'a'或'b'开头的电影,可以运行以下查询:
movies
.allDocs({
include_docs: true,
startkey: 'a',
endkey: 'c'
})
.then(console.log)
.catch(console.log)
startKey
和endKey
参数对于分页API尤其有用。
通过ChangeFeeds实时进行
我们讨论了PouchDB如何使用_rev
字段来跟踪修订,每个修订都指向先前的修订。 PouchDB和CouchDB使用此修订版链进行数据库复制。
但是,此复制算法的含义是,它允许您查看数据库的历史记录,从而使您可以回答诸如
- 自给定时间以来,对数据库进行了哪些更改?
- 对特定文档进行了哪些更改?
这是changes()
API出现的地方。
要获取自时间开始以来的所有更改:
db.changes({
since: 0,
include_docs: true
}).then(function (changes) {
console.log(changes)
}).catch(...)
但是,在Web应用程序中,您通常对查看在初始页面加载后发生的数据库更改更感兴趣,因此您可以相应地更改UI。 PouchDB / CouchDB二人组还为您提供了实时更改提要。
db
.changes({
since: 'now',
live: true,
include_docs: true
})
.on('change', function (change) {
// This is where you can modify UI, based on database change.
// change.id contains the doc id, change.doc contains the doc
if (change.deleted) {
// document was deleted
} else {
// document was added/modified
}
})
.on('error', function (err) {
// handle errors
})
因此,如果您有一个基本的列表应用程序,则可以在一个窗口中添加项目,它们会实时显示在另一个窗口中。
同步:使PouchDB数据超越浏览器
大多数应用程序需要将数据存储在后端,而不仅仅是在浏览器中,因此您可以使用PouchDB在本地存储数据,但可以将其与后端CouchDB实例同步,以便数据可以在任何地方使用,而不仅仅是在该特定的浏览器中。
PouchDB提供了一个非常简单的API来执行此操作。 假设您已经建立了一个远程CouchDB数据库,只需两行JavaScript就可以同步它。
// local database, that lives in the browser's IndexedDB store
var localDB = new PouchDB('mylocaldb')
// remote CouchDB
var remoteDB = new PouchDB('http://localhost:5984/myremotedb')
您可以通过以下方式将本地更改复制到远程数据库:
localDB
.replicate
.to(remoteDB)
.on('complete', function () {
// local changes replicated to remote
}).on('error', function (err) {
// error while replicating
})
但是,由于许多用户可能都可以访问同一数据库,因此能够将更改从远程数据库同步到浏览器更加有用。 PouchDB也为您提供服务。
可以使用以下一行JavaScript来实现双向同步:
// replicates once
localDB.sync(remoteDB);
或进行实时同步:
// keeps syncing changes as they occur
localDB.sync(remoteDB, {live: true})
下一步
PouchDB还具有不断增长的插件和框架适配器生态系统,我们没有足够的空间来使用这些插件和框架适配器 ,但是绝对值得一试。 另外,在使用PouchDB时,您可以使用PouchDB Inspector chrome扩展,它提供了一个漂亮的GUI来查看您的数据库。
这就是PouchDB的介绍性介绍。 它绝对是那里更有趣的数据库之一,我希望您能看到如何使用它来构建脱机优先的实时应用程序。
From: https://www.sitepoint.com/getting-started-with-pouchdb/