这个作业属于哪个课程 | 2302软件工程 |
---|---|
这个作业要求在哪里 | 软件工程实践总结&个人技术博客 |
这个作业的目标 | 完成对软件工程实践课程的总结、个人技术的总结 |
其他参考文献 | 《构建之法》、CSDN |
目录
一、前言
- 学习路线: 很遗憾,在准备篇指定的学习路线,在这一段时间里因为其他课程安排较满以及考取研究生等种种事项没能如期学习。
- 新收获的技术栈: 但是在软件工程实践这门课程里,我为了完成课程的任务,努力去学习了自己之前没有学过,没有尝试过的技术与框架:
- Vue3前端框架
- java SpringBoot后端框架
- maven工具使用
- Gsonformat解析json文件
- fastjson解析处理json数据
- 微信小程序原生开发与云开发
- 项目部署服务器(nginx管理代理,axios网络请求访问,java SpringBoot注解)
- 团队开发角色: 部分全栈开发(可以这么说吗= =) ,在团队项目中,我做了以下事项:
- 需求分析
- 前后端接口设计
- 前端部分结构、样式设计
- 后端大部分云函数代码实现
- 部分测试
- 本篇博客,我将主要讲解微信云开发数据库多表连接查询的技术
二、技术概述
- 这个技术是做什么的: 查询微信云数据库的多个表,合成为一个查询列表而返回。
- 学习技术的原因: 当要获取关联到多个数据库表的数据时,需要进行数据库连接查询。
- 技术的难点: 官方的说明文档不太好理解,用例不够全面,要用到的函数或者方法的用法难以理解。
三、技术详述
对于多表连接查询,有两种做法
第一种: 查完一表,再查一表,不用到微信小程序开发的聚合aggregate() 函数
第二种: 进行表的连接,用到微信小程序开发的聚合aggregate() 函数
- 拿一个简单的例子来进行说明:
- 帖子显示评论者的头像、昵称、评论信息
- 这涉及到了三个表的查询,post、comment、user,那么我们要怎么做呢?
- 云代码如下:
const cloud = require('wx-server-sdk');
cloud.init();
const db = cloud.database();
exports.main = async (event, context) => {
try {
const result = await db.collection('post').where({
_id: event._id
}).get();
const userResult = await db.collection('user').where({
number: result.data[0].user_id
}).get();
const commentResult= await db.collection('comment').aggregate()
.match({
post_id: event._id,
status:2
})
.lookup({
from: 'user',
localField: 'author_id',
foreignField: 'number',
as: 'author_user',
})
.sort({send_time:-1})
.end()
const postWithMetaData={
data:result,
nickname:userResult.data[0].nickname,
avatar:userResult.data[0].avatar,
comments:commentResult.list
}
if (result.errMsg === 'collection.get:ok') {
// 查询成功
return {
errMsg: 'cloud.callFunction:ok',
data: postWithMetaData
};
} else {
// 查询失败,这种情况通常不会发生,因为错误会抛出异常
return {
result,
errMsg: 'cloud.callFunction:fail',
message: '查询失败'
};
}
} catch (e) {
console.log(e)
}
};
- 调用函数代码如下:
getPostDetails:function(){
// 根据任务ID查询任务详情,可能涉及到调用云函数或查询数据库
// 此处示例省略具体查询逻辑
wx.cloud.callFunction({
name: 'getPostDetails',
data: {
_id:this.data.taskId
},
}).then(res => {
if (res.result.errMsg === 'cloud.callFunction:ok') {
var app=getApp()
this.setData({
postDetail: res.result.data.data.data[0], // 假设云函数返回的任务数组字段为 tasks
nickname:res.result.data.nickname,
comments:res.result.data.comments,
currentId:app.globalData.number
});
if(res.result.data.avatar===undefined){
this.setData({
isAvatarUndefined:true
})
}
else{
this.setData({
avatar:res.result.data.avatar,
})
}
const isCreator = this.data.postDetail.user_id === this.data.currentId;
} else {
wx.showToast({
title: '出错了TAT'
});
}
})
},
- 如图所示
comment
表中存储着post
表的_id
作为外键post_id
,author_id
作为user
表的number
字段的外键。
- 第一步:找到表与表的外键关系
- 要在post页面显示评论,要去找comment对应哪个post。
- 所以我们这时候要获得post_id
- post_id怎么获得呢?(要去想办法获得)
- 我们在帖子列表页面点击具体的帖子,会传输帖子的_id参数给到云函数getPostDetails
- 例如这里点击666这个帖子
- 点击完以后,传入的参数是
event._id
const commentResult= await db.collection('comment').aggregate() .match({ post_id: event._id, status:2 })
- 用传入的参数
event._id
去匹配post_id
(用到aggregate()函数的时候匹配要用match()函数)- 这样获得的comment就全是当前选中post下的comment
- 要在comment中显示user的昵称和头像,就要连接user表进行查询
- comment中的
author_id
作为外键与user表的number
匹配
- 第二步:根据外键关系,连接表
- 这时候就要用到aggregate()函数下的lookup()方法,进行两个表的连接
const commentResult= await db.collection('comment').aggregate() .match({ post_id: event._id, status:2 }).lookup({ from: 'user', localField: 'author_id', foreignField: 'number', as: 'author_user', })
- 从而可以进行两个表的连接,其中
- from:从user表获取user的数据
- localField:当前这个表能够与另一个表匹配的字段
- foreignField:另一个表与localField匹配的字段
- as:两个表连接以后组成的新字段的名称
- 第三步:数据返回与接收
const postWithMetaData={ data:result, nickname:userResult.data[0].nickname, avatar:userResult.data[0].avatar, comments:commentResult.list }
- return 一个数据结构或者查询
- 不能漏掉
await
的异步声明- 使用到
aggregate()
的查询结果,一般返回的是list字段,可以通过.list
来访问- 在云函数里面,就是通过
commentResult.list
来访问,commentResult
是之前设置的数据结构,由await声明接收的数据库聚合查询。- 在前端js代码里面,通过类似这样的代码来获得这个数据。
- 在res的花括号里可以搞很多事情,具体参照我的代码。
- res.result就会获得你的数据,后面的那个data是在云函数里命名的返回值。
.then(res => { this.setData({ comments:res.result.data.comments }) })
四、技术使用中遇到的困难和解决过程
4.1 困难一:返回失败
解决过程:
- 通常是在复制代码的时候,忘记把云函数环境一起复制过去了。
- 除此之外,建议在返回云函数的时候,在异常处理里面输出报错信息,或者在云端上调试**(本地无法显示云端的调试信息)**
- 去网上查。
4.2 困难二:数据库查询返回的值不知道怎么获得
解决过程:
- 通常可以通过在前端的js页面多写几个console.log(res)来获得
4.3 困难三:“我收获的评论”实例处理
解决过程:要处理我收获的评论这个功能,涉及到三个表的查询
- 在本次的团队项目中,只有帖子下面存在评论
- “我”:我的贴子
- “收获的”:有评论
- “评论”:评论内容,评论者的头像昵称
- 从上述例子来看,我们需要连接
post
表,comment
表,user
表,是不是很熟悉?(没有你想象那么简单)
- 重点在于,选择一个中间部分,能够连接其他两个表
- 在这里,很容易就能想到,
comment
表既有post
表的外键post_id
又有user表的外键author_id
- 因此,选择使用两个lookup()函数来完成连接
- 代码如下:
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) // 使用当前云环境
const db = cloud.database();
const _ = db.command
var postid=[]
// 云函数入口函数
exports.main = async (event, context) => {
try {
const post = await db.collection('post').where({
user_id:event.number
}).get()
for(let i=0;i<post.data.length;i++){
postid.push(post.data[i]._id)
}
return db.collection('comment').aggregate()
.match({
status:2,
post_id:_.in(postid)
})
.lookup({
from: 'user',
localField: 'author_id',
foreignField: 'number',
as: 'comments'
})
.lookup({
from: 'post',
localField: 'post_id',
foreignField: '_id',
as: 'post'
})
.sort({send_time:-1})
.end()
.then(res => {return res})
.catch(err => console.error(err))
} catch (e) {
console.log(e)
}
}
- 可以看到在返回的信息里,一条
comment
作为中间件,存着另外两个表的信息。
五、 总结
- 在我的代码中,其实还有一些可以优化的地方,例如可以省略掉不需要的字段,详见可以参考官方文档中replaceRoot,
newRoot
,project三个API的用法。 - 微信云开发数据库的多表连接查询技术是小程序开发中处理复杂数据关系的必须技术。
- 通过精心设计查询逻辑、优化性能和解决实际问题,可以显著提升小程序的数据交互能力和用户体验。
- 掌握这项技术对于小程序开发者来说是一项宝贵的技能。
六、参考博客
- 微信官方文档:数据库集合的聚合操作示例
- csdn博客:微信小程序云开发(云数据库、云函数)的多表联查
- csdn博客:微信云开发–云函数–联表查询( lookup 的使用方法详解)
- csdn博客:微信小程序 | 云函数上的数据库操作
七、软件工程实践总结博客
非常感谢林老师、三位助教、还有结对编程开发的伙伴、团队项目开发的七位伙伴们,本门课程的学习,使我受益匪浅。这些收获,必将活用于我今后的工作学习生活中。
Mon Jun 03 2024 00:18:18 GMT+0800.(at FZU)