JQL联表查询的两种方法
联表查询
为方便文档描述定义以下两个概念:
- 临时表:getTemp方法返回的结果,例:
const article = db.collection('article').getTemp()
,此处 article 就是一个临时表 - 虚拟联表:主表与副表联表产生的表,例:
db.collection(article, 'comment').get()
JQL于2021年4月28日优化了联表查询策略,详情参考:联表查询策略调整
JQL
提供了更简单的联表查询方案。不需要学习join、lookup等复杂方法。
只需在db schema中,将两个表的关联字段建立映射关系,就可以把2个表当做一个虚拟联表来直接查询。
JQL联表查询有以下两种写法:
// 直接关联多个表为虚拟联表再进行查询,旧写法,目前更推荐使用getTemp进行联表查询
const res = await db.collection('order,book').where('_id=="1"').get() // 直接关联order和book之后再过滤// 使用getTemp先过滤处理获取临时表再联表查询,推荐用法
const order = db.collection('order').where('_id=="1"').getTemp() // 注意结尾的方法是getTemp,对order表过滤得到临时表
const res = await db.collection(order, 'book').get() // 将获取的order表的临时表和book表进行联表查询
复制代码
上面两种写法最终结果一致,但是第二种写法性能更好。第一种写法会先将所有数据进行关联,如果数据量很大这一步会消耗很多时间。
1. 这种jql查出来是空数组
db.collection('opendb-poi,uni-id-users').where(`"user_id"==$env.uid`).field("user_id._id,name").get()
原因:
JQL数据库操作 | uniCloud
权限校验
要求组成虚拟联表的各个临时表都要满足权限限制,即权限校验不会计算组合成虚拟联表之后使用的where、field
以下为一个订单表(order)和书籍表(book)的schema示例
// order schema
{"bsonType": "object","required": [],"permission": {"read": "doc.uid==auth.uid","create": false,"update": false,"delete": false},"properties": {"id": { // 订单id"bsonType": "string"},"book_id": { // 书籍id"bsonType": "string"},"uid": { // 用户id"bsonType": "string"}}
}// book schema
{"bsonType": "object","required": [],"permission": {"read": true,"create": false,"update": false,"delete": false},"properties": {"id": { // 书籍id"bsonType": "string"},"name": { // 书籍名称"bsonType": "string"}}
}
复制代码
如果先对主表进行过滤where('uid==$cloudEnv_uid')
,则能满足权限限制(order表的"doc.uid==auth.uid"
)
const order = db.collection('order')
.where('uid==$cloudEnv_uid') // 先过滤order表内满足条件的部分
.getTemp()const res = await db.collection(order, 'book').get() // 可以通过权限校验
如果不对主表过滤,而是对虚拟联表(联表结果)进行过滤,则无法满足权限限制(order表的"doc.uid==auth.uid"
)
const order = db.collection('order').getTemp()const res = await db.collection(order, 'book').where('uid==$cloudEnv_uid').get() // 对虚拟联表过滤,无法通过权限校验
2. 用这种的方式查还是报错:
let where = '"user_id" == $env.uid'let opendbPoi_temp = db.collection('opendb-poi').where('"user_id"==$env.uid').getTemp()const res = await db.collection(opendbPoi_temp,'uni-id-users').where(where).field("user_id.avatar_file as avatar_file,user_id._id,_id,title,tel,address,name").get()console.log('res73', res);
3.上面这种写法确实问题很大,但是改成这种还是报错
后面改成这种就好了,联表查询涉及到权限的最好用上临时表
const db = uniCloud.database();
let opendbPoi_temp = db.collection('opendbpoi').where('"user_id"==$cloudEnv_uid').getTemp()console.log('opendbPoi_temp3', opendbPoi_temp);
let uniIdUsers_temp = db.collection('uni-id-users').field("_id,avatar_file").getTemp()
const res = await db.collection(opendbPoi_temp, uniIdUsers_temp).field("user_id.avatar_file as avatar_file,user_id._id,_id,title,tel,address,name").get()console.log('res77', res);
附带另外一篇别人写的涉及unicloud-db 联合查询的文章
where='project_id.is_show=="show"' 副表的数据需要满足的条件
project_id 主表关联副表的主键
<unicloud-db ref='udb' v-slot:default="{data,pagination,hasMore, loading, error, options}" @error="onqueryerror":page-size="10" @load="resultData":collection='colList'where='project_id.is_show=="show"'>
</unicloud-db>
官方解释:联表查询有以下两种写法,对于数据量稍大的表推荐使用多个临时表组成的数组作为collection,可以在主表的getTemp内先进行过滤减小联表时的性能消耗。
就是先过滤主表,减少数据,然后再联表
colList(){return [db.collection('bank-project-manage-auth-user').where('"user_id"==$env.uid').field('user_id,project_id').getTemp(),db.collection('bank-project-manage-project').where('"is_show"=="show"').field('_id,name,cooperation_name,status,start_time,latest_evaluation,is_show').getTemp()]
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/u013732449/article/details/129152484