第12章 云数据库的高阶用法

云开发的数据库是文档型数据库,相比于关系型数据库比如MySQL,目前还并没有一个比较好的工具类似于phpMyAdmin、MySQL workbench等可以对数据进行可视化管理,那我们应该如何进行管理呢?相比于关系型数据库,它又有哪些优势,在使用过程中应该注意什么,它的数据模型我们应该如何设计,云开发数据库又有哪些特点,在这个章节里我们会进行一个比较详细的阐述。

12.1 数据库的管理

12.1.1 控制台数据库高级操作

在云开发控制台的数据库管理页中可以编写和执行数据库脚本,脚本可对数据库进行增删查改以及聚合的操作,语法与之前的API语法相同。通过数据库脚本的操作可以弥补云开发控制台可视化操作的不足。

脚本已经有了以下全局变量,这样我们就可以直接在脚本里面使用db、指令 _ 和聚合了 $

const db = wx.cloud.database() const _ = db.command const $ = db.command.aggregate

数据库脚本还支持以下表达式,主要是常量、变量和对象的声明以及数据库API的调用表达式:

表达式 支持性 示例
获取属性 支持获取对象的合法属性,对象如 db_,合法属性如 dbcollection 属性 db.collection
函数调用 支持 db.collection()
new 支持 new db.Geo.Point(113, 23)
变量声明 支持变量声明,同时支持对象解构器的声明方式 const Geo = db.Geo
const { Point } = db.Geo
对象声明 支持 const obj = { age: _.gt(10) }
常量声明 支持 const max = 10
负数 支持 const min = -5
注释 支持 // comment
/* comment */
其他 不支持

12.1.2 数据库脚本的实际应用

云开发控制台的数据可视化管理和高级操作还可以实现很多类似于关系型数据库GUI管理工具的功能,毕竟GUI管理的背后就是数据库的脚本操作,更多功能大家可以自己多探索,下面只简单介绍一些例子:

1、批量删除一个集合内的多条记录

我们在开发的过程中,一个集合内有几百条、几千条数据希望全部清空,但是又不想删掉该集合再重建,那应该如何做呢,总不能一条一条删除吧?云开发控制台的可视化操作目前无法做到批量删除一个集合内的多条记录的,但是这个功能我们可以通过控制台数据库高级操作的脚本来轻松进行批量删除,而且还可以创建一个脚本模板,有需要直接点击执行脚本模板做到长期复用。比如我们要删除集合为china的所有记录:

db.collection('china') .where({ _id: _.exists(true) }) .remove()

由于remove请求只支持通过匹配 where 语句来删除,我们可以在where里包含一个条件只要存在_id就删除,由于基本每个记录都有_id,所以就能都删除了。

2、如何给集合内所有数据都新增一个字段

我现在一个集合内有N条数据,由于数据库初期设计的问题,现在想给所有记录新增一个字段,想像进行关系型数据库和Excel新增一列的类似操作,那我应该怎么做呢?同样我们也可以通过控制台数据库高级操作的脚本。比如我们想给china集合内的所有记录都新增一个updateTime的字段,我们可以查询到需要新增字段的记录,然后使用update请求,当记录内没有updateTime字段就会新增:

const serverDate = db.serverDate db.collection('china') .where({ _id: _.exists(true) }) .update({ data: { updateTime: serverDate(), } })

3、如何让记录按照自己预想的方式来排序

我在小程序端批量上传了图片、文章,但是发现它们的显示顺序并不是按照我上传顺序来进行排序,但是我有不少功能却非常依赖排序这个功能,请问我应该怎么做?

批量上传或者你按时间上传,记录的排序并不会按照你认为的顺序来排序是很正常的,查询到的数据的顺序一般也不会是控制台数据库显示的顺序,这个都是非常正常的。你如果对排序有需求,有两种方式,一种是你在开发时就能设计好排序的字段,比如想让文章能按时间来排序,就应该在小程序发表文章时就设置一个字段来记录文章的发布时间,还有一种方式就是手动加字段来自定义,比如轮播的顺序,文章置顶或调整顺序这些,可能你还没有来得及开发相关功能,我们可以使用控制台来自定义,比如给你要排序的记录新增一个字段来自定义你想要的排序顺序,然后再在数据查询时使用orderBy。

4、如何新增多条数据

使用数据库脚本可以实现一次性增加多条数据,目前即使用云函数也无法做到一次增加多条数据库到集合里,在语法上,这两者的差异在于,数据库脚本的data支持Array数组,而API db.collection('').add({data:{}})里的data目前只支持对象Object.

db.collection('china') .add({ data: [ { "_id":"202003041020001", "city":"驻马店", "province":"河南", "city_area":15000, "builtup_area":75.1, "reg_pop":905.0, "resident_pop":696.0, "gdp":1807.69, }, { "_id":"202003041020002", "city":"绍兴", "province":"浙江", "city_area":8279, "builtup_area":199.4, "reg_pop":443.11, "resident_pop":496.8, "gdp":4465.97, } ] })

12.1.3 数据库的导入导出

除了可以使用云开发控制台以及腾讯云网页的云开发控制台对数据库里面的数据进行导入导出以外,在前面我们也介绍了如何使用云函数的后端能力对数据进行导入导出,当然方法也不仅限于此,我们还可以用以下方法:

1、cloudbase-manager-node

我有很多图片、文件批量导入到了云存储,但是我批量获取这些文件的fileID应该怎么做?我的数据库有几十个集合,数据库经常需要备份,每次都要一个个导出非常麻烦,有没有好的方法?

如果大家有类似的功能,大家可以使用cloudbase-manager-node。cloudbase-manager-node的功能非常强大,里面有相比于tcb-admin-node更加丰富的接口,当然这些功能都需要开发人员可以结合接口进行一定的开发。

比如我们想批量获取云存储文件的fileID,可以使用listDirectoryFiles(cloudPath: string): Promise<IListFileInfo[]>列出文件夹下所有文件的名称,也可以使用downloadDirectory(options): Promise<void>来下载文件夹,比如我们想对所有集合的数据进行备份,可以使用listCollections(options: object): object来获取所有集合的名称,然后使用export(collectionName: string, file: object, options: object): object接口来导出所有记录到指定的json或csv文件里。这个在后面我们会大致介绍如何使用。

如果我们想要将云存储里面的文件或文件夹下载备份,将本地电脑的文件或文件夹批量上传到云存储,可以使用Cloudbase CLI工具,这个非常简单,在后面的章节CloudBase CLI会介绍到。

2、HTTP API 中的数据库接口

HTTP API是一个非常通用的方式,无论是哪个平台、哪种语法都可以使用HTTP API对云开发资源里的数据进入导入和导出,这里就不具体介绍代码细节了,我们可以使用以下接口实现导入:

POST https://api.weixin.qq.com/tcb/databasemigrateimport?access_token=ACCESS_TOKEN

可以使用以下接口进行导出:

POST https://api.weixin.qq.com/tcb/databasemigrateexport?access_token=ACCESS_TOKEN

12.1.4 使用回档进行数据备份

云开发提供了数据库回档功能,系统会自动开启数据库备份,并于每日凌晨自动进行一次数据备份,最长保存 7 天的备份数据。开发者可以在数据库操作错误或者出现其他情况时,可在云控制台上通过新建回档任务将集合回档(还原)至指定时间点,实现部分数据找回,保证数据的安全。

回档期间,数据库的数据访问不受影响。回档完成后,开发者可在集合列表中看到原有数据库集合和回档后的集合。这样之前的数据就可以找回来了,并与已有的集合里的数据进行比对。回档已完成后,开发者可以根据情况,在集合列表中选择对应集合,右键重命名该集合名称。看是否启用回档后的数据。