今天给大家带来的是学习专题——从0到1造个小程序 的实战篇6:后端数据库设计&云函数编写。
前面的实战篇,我们已经一步步走下来,将咱们的小程序时间管理小助手包含的4个页面:首页、事项详情页、事项计时页、记录总结页,完成了他们的页面设计和逻辑设计。
「P.S.想要进行回顾的话,可以点击上方的专辑进行哦!」
但是我们知道,仅仅只是把页面和跳转逻辑写出来的话肯定是不够的。而且对于数据的存储和持久化的话,必然是需要用到云端的数据库进行存储,并辅之以操作数据库的方法(增加、删除、修改、查询),才能将一个功能完整、使用体验良好的小程序展现出来。
那么本次实战篇,将会对小程序的后端数据库设计,以及云函数的实战编写进行不同程度的讲解,可能多多少少有些部分会没有涉及到甚至错漏,如果有的话也请麻烦提出啦!那么本篇,我们继续冲冲冲~
本文主要分为3个部分,主要分为云开发环境初始化、数据库设计、云函数实战编写。
❝对于云开发的基础知识如果已经有所遗忘了的话,可以点击【从0到1造个小程序 · 基础篇4:云开发基础知识】进行回顾!
❞
那么接下来,我们就一点点地开始吧~
1. 云开发环境初始化
针对小程序项目中与云开发平台绑定的初始化的话,首先是要在根目录中的app.js
中的onLaunch()生命周期函数中初始化云卡发,部分具体代码如下:
import { CLOUD_ENV_ID } from './config'
App({
onLaunch() {
if (!wx.cloud) {
console.error('请使用 2.2.3 或以上的基础库以使用云能力')
} else {
wx.cloud.init({
traceUser: true,
env: CLOUD_ENV_ID
})
}
})
从import可以看到,我们在./config.js
内部引入了CLOUD_ENV_ID
变量,这个就是我们的云开发id,至于怎么获得自己的这个id的话,详见【从0到1造个小程序 · 基础篇4:云开发基础知识】。
所以,我们在小程序根目录下新建config.js
,写入自己的云开发ID:
//config.js
export const CLOUD_ENV_ID = 'XXXXXXX' // 云开发环境ID
那么,云开发平台环境与咱们的小程序项目的绑定初始化工作就完成了。
2. 数据库设计
❝什么是数据库呢?
数据库是一个"记录保存系统",是"人们为解决特定的任务,以一定的组织方式存储在一起的相关的数据的集合",是"一个数据仓库"。严格地说,数据库是"按照数据结构来组织、存储和管理数据的仓库"。在经济管理的日常工作中,常常需要把某些相关的数据放进这样"仓库",并根据管理的需要进行相应的处理。
例如,企业或事业单位的人事部门常常要把本单位职工的基本情况(职工号、姓名、年龄、性别、籍贯、工资、简历等)存放在表中,这张表就可以看成是一个数据库中的其中一个表。有了这个"数据仓库",我们就可以根据需要随时查询某职工的基本情况,也可以查询工资在某个范围内的职工人数等等。
这些工作如果都能在计算机上自动进行,那我们的人事管理就可以达到极高的水平。此外,在财务管理、仓库管理、生产管理中也需要建立众多的这种"数据库",使其可以利用计算机实现财务、仓库、生产的自动化管理。
❞
那么,针对小程序云开发的数据库的话,又是怎么样的呢?我们来看看官方文档的叙述:
JSON数据库,那么JSON是什么呢?
❝JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。
简单而言,JSON有两种表示结构,对象和数组。对象结构以”{”大括号开始,以”}”大括号结束。中间部分由0或多个以”,”分隔的”key(关键字)/value(值)”对构成,关键字和值之间以”:”分隔,语法结构如代码。其中关键字是字符串,而值可以是字符串,数值,true,false,null,对象或数组。
{
key1:value1,
key2:value2,
...
}数组结构以”[”开始,”]”结束。中间由0或多个以”,”分隔的值列表组成,语法结构如代码。
❞[
{
key1:value1,
key2:value2
},
{
key3:value3,
key4:value4
}
]
其实,对于JSON
的话,在我们页面配置(组件引用)、小程序配置文件的话我们都是有用到了的,还不熟悉的话可以去回顾一下。那么,知道了数据库的一个存储数据的格式以后的话,我们需要思考的就是,我们要存哪些数据,以及怎么设计这两个关键问题了。
(1)存哪些数据
对于这个问题,我们回顾思考一下咱们的小程序的一个业务流程:
首先,用户需要登录才能够使用我们的小程序。那么,存储用户信息就是必要的,而识别唯一用户的话可以通过「openId」进行,所以我们可以直接存储每一个授权登录小程序的用户。
其次,对于登陆以后,小程序的使用核心是“对时间管理事项进行管理”,那么就肯定涉及到的是「时间管理事项」的内容属性的存储。进一步思考,时间管理事项包含哪些属性呢?
回顾之前创建小程序时需要填写的内容:「事项标题」、「所需用时」。同时,因为要事项对应出来是哪一个用户的,所以还需要加一个「userId」绑定;因为是时间管理,还有考虑到后面事项进行记录的用时,以及首页的列表展示需要,所以我们还需要加上「已用时」、「事项最后更新时间」、「事项创建时间」。
针对事项详情以及记录总结页的话,我们知道,对于每一个时间管理事项,都会有对应该事项的一个记录列表。所以也应该创建一个对应每一个事项的记录列表,对应实现方式通过绑定一个事项id
eventId
。对于记录列表使用一个records数组,里面存储每一次记录的:「开始时间」、「结束时间」、「总结内容」、「持续时间」。
(2)怎么设计
针对以上的三个部分,对应的就是3张表啦!以下是设计/创建数据库表集合的一个流程:
- 所以我们打开我们各自的云开发界面:
- 点击数据库栏目:
- 在云开发数据库中创建
users
、events
、event-records
三个集合。
其中user
代表用户集合;events
代表事项详细信息集合;event-records
代表各事项记录总结集合。
- 在
event-records
中添加eventId
为唯一索引,在users
中添加_openid
为唯一索引。
以上,就是关于数据库的设计了,其中关于对数据库存储哪些哪些数据这一块需要加深记忆,因为在后面的云函数编写中需要着重使用。
3. 云函数实战编写
从之前的页面逻辑设计中,相信大家都有看到像下面的这一类函数:
static editEventTitle(eventId, eventTitle, eventTime) {
return wx.cloud.callFunction({
name: 'editEventTitle',
data: {
eventId,
eventTitle,
eventTime
}
})
}
static getEventData(eventId) {
return wx.cloud.callFunction({
name: 'getEventData',
data: { eventId }
})
}
static removeEvent(eventId) {
return wx.cloud.callFunction({
name: 'removeEvent',
data: { eventId }
})
}
可以看到其中他们的共同点都有wx.cloud.callFunction
,然后内部再指定name
、data
,给予页面JS调用以后,就能调取数据了。那长这个样子的这类函数,到底是什么来的呢?
其实,看看cloud.callFunction
,就可以隐约猜到,这个就是微信所提供的调用云函数的API(应用程序接口,可以理解为提供能够使用的方法)。
那么,既然我们之前声明了这么多的云函数名称,那么现在小程序后端的开发,就要将这些方法给一一实现了。所以,我们先来看看,我们之前声明了多少个云函数方法呢?水水已经整理好了,见下:
login //注册openid
removeEvent //删除单个事项
addEventRecord //添加事项记录
addUser //创建用户
createEvent //创建事项
editEventTitle //修改事项标题与用时
getEventData //获取单个事项信息
getEventList //获取全部事项
❝对于我们这个小程序项目中所涉及到的云函数的话,都属于操作数据库的方法,而且对于编写云函数的话也是有一套模板可供修改定制的,所以别看云函数这么多,其实写起来也并不难。
同时,对于该部分的学习资料的话可以看往期推文【从0到1造个小程序 · 基础篇4:云开发基础知识】中的数据库部分进行回顾,看了之后再进行云函数的实战,一定会有一种畅快之感哦!
❞
那么我们该如何去编写云函数呢?首先,右键小程序环境,选择【新建node.js云函数】,按照上面所声明方法名进行命名,即可完成云函数的新建。
然后可以看到,新建云函数以后出现了3个文件,而我们需要进行编辑就是index.js
:
那么,我们先写一个login云函数方法作为栗子吧:
对于login方法的话,其实就是将用户的openId获取并保存到user表中,这个操作听起来就不难,我们直接看看代码的,其中有必要的注释加以说明:
//cloudfunctions\login\index.js
const cloud = require('wx-server-sdk')
cloud.init({
env: 'XXXXX' //你的云开发id
})
//获取数据库实例
const db = cloud.database()
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
//获取openid
const openId = wxContext.OPENID
//操作数据库的users集合根据openid获取数据
const result = await db
.collection('users')
.where({
_openid: openId
})
.get()
const idData = result.data[0]
//如有则返回id,否则userid返回空
return {
userId: idData && idData._id && idData._openid ? idData._id : null,
openId
}
}
编辑完成并保存后,还需要部署云函数,才能够真正将云函数应用到我们的小程序项目中的,具体方法的话,只需要右键对应云函数文件夹,选择【上传并部署:云端安装依赖(不上传node_modules)】,即可完成云函数的部署,然后小程序就能够调用我们的云函数了。没错,就是这么简单!
那么,login云函数编写完成。
像这样子的云函数还有7个!
不过没事,具体的云函数的用途和说明的话也已经在上面列举了,大家也可以先试一试如果自己写的话会怎么去写,还是不会需要加深记忆的话也可以再看看,多学学。以下的话,将展示剩余所有的云函数编写示例,其中也有必要的代码注释辅助理解。
那么,代码轰炸开始了!
//cloudfunctions\removeEvent\index.js
const cloud = require('wx-server-sdk')
cloud.init({
env: 'XXXXXX'
})
//新建数据库实例
const db = cloud.database()
const _ = db.command
exports.main = async (event, context) => {
const { eventId } = event
//如果没有该事项对应的id,则直接结束
if (!eventId) {
return
}
try {
await db
//根据eventId删除与该事项相关的记录条目
.collection('event-records')
.where({
eventId
})
.remove()
//根据eventId删除与该事项条目
await db
.collection('events')
.doc(eventId)
.remove()
} catch (e) {
console.log(e)
}
}
//cloudfunctions\addEventRecord\index.js
const cloud = require('wx-server-sdk')
cloud.init({
env: 'XXXXXXXXXXX'
})
const db = cloud.database()
const _ = db.command
exports.main = async (event, context) => {
//从参数中获取到事项id,开始时间,结束时间,总结内容,持续时间
const { eventId, beginDate, endDate, summary, time } = event
//若没有对应事项,则返回
if (!eventId) {
return
}
try {
//根据事项id及参数内容更新插入新纪录
await db
.collection('event-records')
.where({
eventId
})
.update({
data: {
records: _.push([
{
summary,
beginDate,
endDate,
time
}
])
}
})
//在事项events表中更新最后更新时间
await db
.collection('events')
.doc(eventId)
.update({
data: {
time: _.inc(parseInt(time)),
lastUpdate: endDate
}
})
} catch (e) {
console.log(e)
}
}
//cloudfunctions\addUser\index.js
const cloud = require('wx-server-sdk')
cloud.init({
env: 'XXXXXXX'
})
const db = cloud.database()
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
//新增用户,在users表中用openid新插入到表中
try {
return await db.collection('users').add({
data: {
_openid: wxContext.OPENID
}
})
} catch (e) {
console.log(e)
}
}
//cloudfunctions\createEvent\index.js
const cloud = require('wx-server-sdk')
cloud.init({
env: 'XXXXXXX'
})
const db = cloud.database()
const _ = db.command
exports.main = async (event, context) => {
//从参数中获取到事项标题,用户id,事项预计用时
const { eventTitle, userId, eventTime } = event
//如果有参数为空则方法结束
if (!eventTitle || !userId || !eventTime) return
try {
//根据参数以及时间在events表中插入事项
const event = await db.collection('events').add({
data: {
userId,
title: eventTitle,
eventTime:eventTime,
createDate: new Date(),
lastUpdate: null,
time: 0
}
})
//事项记录表中也需要用eventsId初始化该事项的记录表
await db.collection('event-records').add({
data: {
eventId: event._id
}
})
} catch (e) {
console.log(e)
}
}
//cloudfunctions\editEventTitle\index.js
const cloud = require('wx-server-sdk')
cloud.init({
env: 'XXXXXXX'
})
const db = cloud.database()
exports.main = async (event, context) => {
//根据参数获取到id、事项标题、所需时间
const { eventId, eventTitle, eventTime } = event
//若其中有一项为空则返回
if (!eventId || !eventTitle || !eventTime) return
try {
//根据eventid更改对应事项的属性,并返回
const result = await db
.collection('events')
.doc(eventId)
.update({
data: {
title: eventTitle,
eventTime:eventTime
}
})
result.data = {
eventId,
eventTitle,
eventTime
}
return result
} catch (e) {
console.log(e)
return e
}
}
//cloudfunctions\getEventData\index.js
const cloud = require('wx-server-sdk')
cloud.init({
env: 'XXXXXX'
})
const db = cloud.database()
const _ = db.command
exports.main = async (event, context) => {
//从参数中获取到事项id
const { eventId } = event
//若为空则直接结束
if (!eventId) {
return
}
try {
//根据事项id获取对应事项数据
const eventInfo = await db
.collection('events')
.doc(eventId)
.get()
//根据事项id获取该事项的所有记录
const eventRecords = await db
.collection('event-records')
.where({
eventId
})
.get()
//根据上面的两个查询拼接返回
return { eventInfo, eventRecords }
} catch (e) {
console.log(e)
}
}
//cloudfunctions\getEventList
const cloud = require('wx-server-sdk')
cloud.init({
env: 'XXXXXX'
})
const db = cloud.database()
const _ = db.command
exports.main = async (event, context) => {
//根据参数获取用户id
const { userId } = event
if (!userId) {
return
}
try {
//根据用户id从事项表中获取所有事项
return await db
.collection('events')
.where({
userId
})
.get()
} catch (e) {
console.log(e)
}
}
所有云函数编写完成后,再分别进行部署,云函数就能够被自由调用了!
以上,就是本次后端设计的主要内容。至此,小程序的基本功能已经全部完成。
■ Over ■
历史推荐
从0到1造个小程序 · 实战篇4:页面设计之计时页 从0到1造个小程序 · 实战篇5:页面设计之记录总结页 从0到1造个小程序 · 实战篇3:页面设计之事项详情页 从0到1造个小程序 · 实战篇2:页面组件化设计&首页逻辑设计 ★我是水水
我们下期再见
★本公众号不具备留言功能
有什么问题的话欢迎在后台输入框中回复哦~