谈谈 lowdb 的使用

LT;DR;

博主在使用 lowdb 时遇到了几个需求光靠 lowdb 提供的 API 无法实现。其实 lowdb 是基于 Lodash 的,可以使用 Lodash 提供的 API 实现自己的一些需求。比如下面提到的「数组删除元素」与「深查询」。

基本上查看下面的文档就行了。

lowdb 的 Github 仓库

Lodash 官方文档

PS:配合 TypeScript 使用 lowdb 时,如果要使用 Lodash 的 API(当然,直接使用 Lodash 也同理。),即便你安装了 @types/lodash ,仍然有许多方法会报编译错误。这是因为声明还没覆盖完 lodash 的方法。使用时可以忽略这些错误或者设置 //@ ts-ignore 忽略编译报错。

原文

之前在 关于标记 这篇博文写到想做一个标记的本地应用,最近感觉想法成型了,于是开始研究怎么做出来。

中间种种过程略去不提,但谈我最后选用 electron 来开发,然后需要用到数据库。没怎么比较,选择了 lowdb 这个基于json 的小型数据库。

先贴官方链接。

lowdb 的 Github 仓库

然后入门教程看的这篇:Electron-vue开发实战2——引入基于Lodash的JSON数据库lowdb


使用过程中有几个需求没找到明确的解决方式。

比如对数组元素的删除。例如有一个数组:

1
["快乐","开心","悲伤"]

没有提供直接删除数组元素的方法。

其次,没在官方文档找到 「对象A 作为 对象B 的属性时,如何通过查询 对象A 的属性 获取 对象B」,即深查询的方法。

有点绕吧,还是举个例子:

1
2
3
4
5
6
7
{
name : "车",
component : {
"轮胎" : "香港造"
……
}
}

没有直接通过查询 轮胎 获取 这整块数据的方式。


对官方提供的几个 api 翻来过去的组合搭配也没能成功。

看到提供了自定义操作的方法,差点准备自己实现了。

1
2
3
4
5
6
7
8
9
db._.mixin({
second: function(array) {
return array[1]
}
})

db.get('posts')
.second()
.value()

其实这个就是 lodash 提供的接口……

另外 lodash-id 等插件就是通过这个 api 注入进去的。

太沙雕了。

这不是很复杂的操作,不应该这么复杂啊……

翻读了几遍文档,才注意到 lowdb 基于 Lodash 的。

眼前一亮,去翻了一下 Lodash 的 API……

Lodash 官方文档


上面提到的第一个问题,删除数组属性,可以通过 Lodash 的 remove 实现。如下:

1
2
3
4
5
6
7
8
// 删除 标签
export function deleteTagByName(tagName) {
db.read().get('tag')
.remove(function(n) {
return n === tagName;
})
.write();
}

而深查询可以这样:

1
2
3
4
5
export function getItemByName(name) {
return db.read().get('item')
.filter(["template_style.name", name])
.value();
}

传一个具有两个元素的数组,就会分别匹配键值。


稍微复杂点的例子

来一个数组与深查询组合拳……

数据如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[ {
id: 7,
template_name: "单曲",
template_style: {

"name": "菊次郎的夏天",
"作者": "久石让",
"状态": "听过",
"标记时间": "2019-02-10"

},
tag_name: ["童年"]
}, {
id: 8,
template_name: "单曲",
template_style: {

"name": "荡起双桨",
"作者": "佚名",
"状态": "听过",
"标记时间": "2019-03-10"

},
tag_name: ["童年", "恐怖"]
}]

如何通过 标签名 查询该 标签 下的 所有条目?

可以这样:

1
2
3
4
5
6
7
8
9
10
// 通过 标签名 获取 条目
export function getItemsByTagName(tagName) {
return db.read().get('item').filter(function (item) {
if (item.tag_name.indexOf(tagName) !== -1) {
return true;
} else {
return false;
}
}).value();
}