前端数据库 本地离线存储工具 PouchDB 简单入门(以Node.js场景为例)
前言
最近在做一个基于 Electron
和 Vue
的桌面应用程序的个人项目,需要在本地存储和展示本地音频文件的索引数据。过程中也是踩坑无数,跟大家分享一下这段经历。
离线存储工具的选择
离线存储,实现的方式有很多。最简单的便是我们熟悉的浏览器端离线存储,如 LocalStorage
和 SessionStorage
,又或是 IndexedDB
和 Web SQL
。 以上四种离线存储在项目中,均可以通过 Electron
渲染进程中的 Chromium
内核来实现。一些轻量级的第三方库,如 ImmortalDB、web-storage-cache对浏览器离线存储做了一些扩展,但这些库的维护情况还是不太让人满意。不过,这其中的localForage也还是让人眼前一亮。
受限于浏览器内核的环境,以上方法不能很好满足我的需求,于是只能寻找 node.js
端的存储工具,这其中又分两类,一类是js本身实现(如NeDB和PouchDB),另一类则是成熟的数据库软件(如 MySQL
和 MongoDB
)。
按功能和性能来讲,数据库绝对是最优的选择,但不是很符合我的 Electron
应用程序的定位,1、它们体积非常庞大,需要打包进用户的安装包(实现起来有难度,也没几个让普通的用户能够忍受一个小小软件在自己的计算机上装 MySQL
);2、功能庞大,杀鸡焉用牛刀?
于是,不占空间、轻量又方便打包的 NeDB
和 PouchDB
进入了决赛圈。考虑到 NeDB
是明文存储,功能单一,又年久失修。我就果断选择了隔壁 PouchDB
。
PouchDB 入门
我们先来看看 PouchDB
官网 是如何介绍这个产品的:
PouchDB
在浏览器和 Node.js
环境下都可以运行,轻量便携、上手简单等优点。PouchDB
在浏览器中默认使用 IndexedDB
,若当前环境不支持,则回退到 Web SQL
。在 Node.js
环境中则会以特定格式的本地文件存储数据。官方文档的这个部分详细介绍了在不同环境下的工作形式?Adapters。
安装
官方文档中给出了两种方式,分别是 CDN
和 npm
:
<script src="//cdn.jsdelivr.net/npm/pouchdb@7.2.1/dist/pouchdb.min.js"></script>
npm install --save pouchdb
初始化
在 node
环境中引用 pouchdb
,通过PouchDB
这个构造函数来创建一个数据库实例:
const PouchDB = require('pouchdb')
// 创建在根目录下database文件夹下名为my_database的数据库
const db = new PouchDB('database/my_database')
new PouchDB([name], [options])
方法接受数据库名称与配置项作为参数(具体配置项参见文档)。name
这个参数除了接受名称外,还可以传入远程 CouchDB
数据库地址,比如 const db = new PouchDB('http://pouch-db.com/my-db')
。
不过,官方文档对 node
环境下数据库存储位置并未做足够的说明。 在这里指出,在 node
环境下name可以为相对路径和绝对路径,如下:
// 在{root}/database/my_database目录下创建
const db = new PouchDB('database/my_database')
// 在C:/Code/test/test_pouchdb目录下创建
const db2 = new PouchDB('D:/Code/test/test_pouchdb')
基本操作
数据库最基本的无非就是又快又方便地做 CRUD
。我们来快速实现一下 PouchDB
的基本操作。所有相关操作均可以在其API文档中找到传送门。
增
首先,我们需要定义要存储的数据格式:
const myData = {
_id: String,
title: String
}
其次,最好使用统一的函数去增添数据,因为在 PouchDB
中并没有严格的 schema
。我们使用 db.put(doc, [options], [callback])
方法添加或修改数据。
需要指出, PouchDB
除了用传统的 callback
,还支持更主流的 Promise
与 async
。
// * 使用函数包装 新增数据 的方法
function addData(title) {
// 数据格式
const data = {
_id: new Date().toISOString(),
title: text
}
// 增改方法
db.put(data, function cb(err, result) {
if (err) {
console.error(err)
} else {
console.log(result)
}
})
}
我们使用 addData()
方法创建一个 title
为 'helloPouchDB'
的数据,然后看一看该数据包含些什么:
addData('helloPouchDB')
回调函数中的 result
返回了新增的状态、数据的 id
和 rev
。数据中除了 title
也有相应的 _id
和 _rev
。
// result
{
ok: true,
id: '2020-12-04T12:54:13.638Z',
rev: '1-a2436e9326998a520a759f2a274e166b'
}
// 保存的那个data
{
title: 'helloPouchDB',
_id: '2020-12-04T12:54:13.638Z',
_rev: '2-565fec0bf70044cc51d24a8379139f8e'
}
需要注意的是,修改数据需要指定当前修改数据项的 _rev
(创建的时候默认就有)。 比如这样:
db.put({
title: 'Nice to meet you',
_id: '2020-12-04T12:54:13.638Z',
_rev: '2-565fec0bf70044cc51d24a8379139f8e'
})
查
从数据库中根据id查找(fetch)数据,需要用到 db.get(docId, [options], [callback])
,如 db.get(_id)
。配置项中可以指定一个或者多个 rev
,其他的配置项参考文档。
如果需要获取多条数据,则需要使用 db.allDocs([options], [callback])
(文档传送门)。在配置项中可以指定 skip
和 limit
来实现分页功能。
function showData() {
db.allDocs({
include_docs: true, // 返回的数据中默认只有id和rev,带上数据需传true
descending: true, // 降序排列
skip: 20,// 第3页
limit: 10 // 每页10条
})
.then((res) => {
console.log(res)
})
.catch((err) => {
console.error(err)
})
}
返回的数据,包含了总条数 total_rows
、跳过的条数 offset
、与数据的数组 rows
。格式如下:
{
total_rows: 1,
offset: 0,
rows: [
{
id: '2020-12-04T13:00:26.358Z',
key: '2020-12-04T13:00:26.358Z',
value: { rev: '1-6da27cff722c24cfe38fb09be78f8576' },
doc: {
title: 'helloPouchDB',
_id: '2020-12-04T13:00:26.358Z',
_rev: '1-6da27cff722c24cfe38fb09be78f8576'
}
}
]
}
接下来是最重要的一个查询方法 db.find(request [, callback])
。这个方法允许通过数据的字段来查询数据 文档传送门。需要注意,这个方法需要引入 pouchdb-find
插件 。
# 安装
npm install --save pouchdb-find
const PouchDB = require('pouchdb')
// 注入插件
PouchDB.plugin(require('pouchdb-find'))
db.find()
通过 selector
指定查询内容、 fields
指定返回的内容包含的字段。 selector
也可以使用 $lt
、 $gt
等过滤器指定特殊的查询条件。与 db.allDocs()
一样,可以指定 skip
和 limit
。
db.find({
selector: {
title: 'helloPouchDB',
},
fields: ['_id', 'name'],
})
改、删
结合 新增 与 查询 这两种方法, 我们变可以获取已有的数据并使用 db.put()
方法对其进行修改:
// 查询
db.find({
selector: {
title: 'helloPouchDB',
},
})
.then((res) => {
// 获取该数据
const result = res.docs[0]
// 修改数据
result.title = 'Nice to meet you'
// 修改并写入
db.put(result)
.then((res) => {
console.log('yes!')
})
.catch((err) => {
console.error(err)
})
})
.catch((err) => {
console.error(err)
})
删除数据 可以通过 db.remove(doc, [options], [callback])
方法,该方法除了接受 doc
对象外,也可以通过 id
与 rev
删除数据。
// 方式1 - 获取实例并删除
db.get(_id, function(err, doc) {
if (err) { return console.log(err) }
db.remove(doc, function(err, response) {
if (err) { return console.log(err) }
})
})
// 方式2 - 通过 id 和 rev 删除
db.remove(doc._id, doc._rev, function(err, response) {
if (err) { return console.log(err) }
})
})
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!