前面说过,NodeBB 支持 mongodb 或 redis 作为存储数据库。这种使用 NoSQL 数据库的做法我很欣赏,有时候写插件要给数据库添加某个字段的时候非常方便,直接加就行。比如给 Topic 添加一个 externalLink 属性。
其实 NodeBB 刚开始 0.x 版的时候还只支持 Redis, 所以它的数据存储格式就这几种: hashes, sets, sortedsets and lists。后来经过某个版本的 Merge 后,依靠社区的力量终于支持 Mongodb 了, 有牛人用 Mongodb 来实现了 hashes, sets, sortedsets and list 这几种特殊的格式。 以至于现在 NodeBB 在数据库层的接口完全是一致的, Views 和 Controller 调用存储的时候完全不用管是 Redis 还是 Mongodb.
这是如何实现的呢?
查看源代码可以看到,在 src/databases
下有 mongo 和 redis 对于 hash, list, sets 和 sorted set 的各自实现,上层调用时使用它们统一抽象的接口名。比如 setObject
,它们在 mongo 和 redis 下的实现是这样的:
1 |
|
上层调用数据库的时候无需区分使用哪个 db:
1 | var db = require('./database'); |
NodeBB 其实就是这样简单粗暴地检测调用哪个数据库的:
1 | var nconf = require('nconf'), |
这样做对于 mongodb 的后果就是整个数据库看上去只有一张表叫 objects(除了服务器 session 和 search 索引用到了其他表),并通过 _key 来区分不同数据分类。
比如,这样查询某个用户表的信息:
1 | > db.objects.find({_key:"user:100"}).pretty() |
这是官网的例子,详请见 NodeBB database structure.
NodeBB 将很多需要统计或排序的字段存储在 sorted set 中,一般使用 value 表示排序的字段名,score 表示统计数字。
比如 users:postcount
就是一个 sorted set, 其中存储了每个用户对应的 post count, 其中 value 表示 uid, score 表示 post count. 如果你熟悉 redis 的话,应该知道这是什么意思。
再举个例子,我在做 nodebb-plugin-sso-github2 的时候,用到的数据库有 hash 类型的 githubid:uid
和 sorted set 类型的 email:uid
, 各自保存了 github 和 user ,email 和 user 之间的对应关系。
此前我在创建 category 的时候,没注意将 category 的 slug 都设置成了中文,与 category name 同名。在 mongo 下可以这样更改(以我的数据库为例):
db.objects.update({_key: "category:10"}, {$set: {slug: "10/technique"}})
如你看到此文,还有更多的疑问或不同的见解, 欢迎来到 v2mm 上讨论。
v2mm 是我创建的一个自由职业者论坛,欢迎加入 v2mm, winter is coming.