uniCloud ---- JQL语法 连表查询

2024-01-29 18:36

本文主要是介绍uniCloud ---- JQL语法 连表查询,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

JQL数据库操作

JQL流程图解

JQL的限制

单表查询

联表查询

新增

修改

删除

联表查询

例子 

字段过滤field

字段别名as

限制查询记录的条数limit

只查一条记录getone


JQL数据库操作

JQL,全称 javascript query language,是一种js方式操作数据库的规范。

  • JQL大幅降低了js工程师操作数据库的难度,比SQL和传统MongoDB API更清晰、易掌握。
  • JQL支持强大的DB Schema,内置数据规则和权限。DB Schema 支持uni-id,可直接使用其角色和权限。无需再开发各种数据合法性校验和鉴权代码。
  • JQL利用json数据库的嵌套特点,极大的简化了联表查询和树查询的复杂度,并支持更加灵活的虚拟表。
const db = uniCloud.database()// 使用`jql`查询list表内`name`字段值为`hello-uni-app`的记录
db.collection('list').where('name == "hello-uni-app"').get().then((res)=>{// res 为数据库查询结果}).catch((err)=>{// err.message 错误信息// err.code 错误码})

JQL流程图解

下图包括clientDB及云函数内使用jql扩展库的调用流程

前端编写数据库增删改查代码接收云端返回结果橙色为开发者要做的工作紫色为clientDB,包括前端和云端箭头流程为运行流程ClientDBJSAPIClientDB组件(仅支持查询)前端ClientDB云端其他工作事项云函数DB-Permission校验模块

1.DBSchema配置权限解析前端请求,分析前端的uni-id身份、要操作的数据表、字段和增删改查动作内调用驳回然后从DBSchema配置读取数据表、字段、增删改查动作的权限

2.DBSchema配置字段jql扩展确认该前端用户是否有权进行这次数据库操作校验规则(如果是查询和通过删除,无需配置)Validator字段校验模块

3.编写schema扩展驳回如果是查询和删除,本模块将直接放行;(数据库触发器)(可如果是新增和修改记录,则从DBSchema配置获取数据字段的合法性,如是否必填、是选)否符合某个正则规则,以确认对数据字段内容的修改是否合法通过处理扩执行数据库触发器before阶段展库返可选模块。
可以通过编程对前端传的数据进行二次处理,也可以在执行数据库操作前执行一些前置操作回信息执行数据库操作,获取json结果执行数据库触发器after阶段可选模块。可以通过编程对将要回传给前端的数据进行二次处理;也可以在此处对数据库进行二次修改,比如前端查询一篇文章详情后,在此处对文章的阅读数+1

JQL的限制

  • 会对数据库操作进行序列化,除Date类型、RegExp之外的所有不可JSON序列化的参数类型均不支持(例如:undefined)
  • 为了严格控制权限,禁止使用set方法
  • 为了数据校验能严格限制,更新数据库时不可使用更新操作符db.command.inc
  • 更新数据时键值不可使用{'a.b.c': 1}的形式,需要写成{a:{b:{c:1}}}形式

单表查询

下面这些方法必须严格按照下面的顺序进行调用,其他方法需要在这些方法之后调用(不限制顺序)

collection
aggregate
geoNear // 新增于 HBuilderX 3.6.10
doc
where
field
groupBy
groupField

联表查询

临时表可以使用以下方法(需按照下面的顺序调用)

collection
geoNear // 新增于 HBuilderX 3.6.10
where
field
orderBy
skip
limit
getTemp

虚拟联表可以使用以下方法(需按照下面的顺序调用)

collection
foreignKey
where
field
groupBy
groupField
distinct
orderBy
skip
limit
get

新增

仅允许collection().add()这样的形式

修改

仅允许以下两种形式

db.collection('xx').doc('xxx').update({})
db.collection('xx').where('xxxx').update({})

删除

仅允许以下两种形式

db.collection('xx').doc('xxx').remove()
db.collection('xx').where('xxxx').remove()

联表查询

为方便文档描述定义以下两个概念:

  • 临时表: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表进行联表查询

上面两种写法最终结果一致,但是第二种写法性能更好。第一种写法会先将所有数据进行关联,如果数据量很大这一步会消耗很多时间。详细示例见下方说明

关联查询后的返回结果数据结构如下:

通过HBuilderX提供的JQL数据库管理功能方便的查看联表查询时返回数据的结构

主表某字段foreignKey指向副表时

{"主表字段名1": "xxx","主表字段名2": "xxx","主表内foreignKey指向副表的字段名": [{"副表字段名1": "xxx","副表字段名2": "xxx",}]
}

副表某字段foreignKey指向主表时

{"主表字段名1": "xxx","主表字段名2": "xxx","主表内被副表foreignKey指向的字段名": {"副表1表名": [{ // 一个主表字段可能对应多个副表字段的foreignKey"副表1字段名1": "xxx","副表1字段名2": "xxx",}],"副表2表名": [{ // 一个主表字段可能对应多个副表字段的foreignKey"副表2字段名1": "xxx","副表2字段名2": "xxx",}],"_value": "主表字段原始值" // 使用副表foreignKey查询时会在关联的主表字段内以_value存储该字段的原始值,新增于HBuilderX 3.1.16}
}

例子 

比如有以下两个表,book表,存放书籍商品;order表存放书籍销售订单记录。

book表内有以下数据,title为书名、author为作者:(副表)

{"_id": "1","title": "西游记","author": "吴承恩"
}
{"_id": "2","title": "水浒传","author": "施耐庵"
}
{"_id": "3","title": "三国演义","author": "罗贯中"
}
{"_id": "4","title": "红楼梦","author": "曹雪芹"
}

order表内有以下数据,book_id字段为book表的书籍_id,quantity为该订单销售了多少本书:(主表)

{"book_id": "1","quantity": 111
}
{"book_id": "2","quantity": 222
}
{"book_id": "3","quantity": 333
}
{"book_id": "4","quantity": 444
}
{"book_id": "3","quantity": 555
}

如果我们要对这2个表联表查询,在订单记录中同时显示书籍名称和作者,那么首先要建立两个表中关联字段book的映射关系。

即,在order表的db schema中,配置字段 book_id 的foreignKey,指向 book 表的 _id 字段,如下

// order表schema
{"bsonType": "object","required": [],"permission": {"read": true},"properties": {"book_id": {"bsonType": "string","foreignKey": "book._id" // 使用foreignKey表示,此字段关联book表的_id。},"quantity": {"bsonType": "int"}}
}

book表的DB Schema也要保持正确

// book表schema
{"bsonType": "object","required": [],"permission": {"read": true},"properties": {"title": {"bsonType": "string"},"author": {"bsonType": "string"}}
}

schema保存后,即使用JQL查询。查询表设为order和book这2个表名后,即可自动按照一个合并虚拟联表来查询,field、where等设置均按合并虚拟联表来设置。

// 客户端联表查询
const db = uniCloud.database()
const order = db.collection('order').field('book_id,quantity').getTemp() // 临时表field方法内需要包含关联字段,否则无法建立关联关系
const book = db.collection('book').field('_id,title,author').getTemp() // 临时表field方法内需要包含关联字段,否则无法建立关联关系
db.collection(order, book) // 注意collection方法内需要传入所有用到的表名,用逗号分隔,主表需要放在第一位.where('book_id.title == "三国演义"') // 查询order表内书名为“三国演义”的订单.get().then(res => {console.log(res);}).catch(err => {console.error(err)})

字段过滤field

一定要加上关联的id

查询时可以使用field方法指定返回字段。不使用field方法时会返回所有字段

field可以指定字符串,也可以指定一个对象。

field中可以使用所有数据库运算方法

  • 字符串写法:列出字段名称,多个字段以半角逗号做分隔符。比如db.collection('book').field("title,author"),查询结果会返回_idtitleauthor3个字段的数据。字符串写法,_id是一定会返回的

复杂嵌套json数据过滤

如果数据库里的数据结构是嵌套json,比如book表有个价格字段,包括普通价格和vip用户价格,数据如下:

{"_id": "1","title": "西游记","author": "吴承恩","price":{"normal":10,"vip":8}
}

那么使用db.collection('book').field("price.vip").get(),就可以只返回vip价格,而不返回普通价格。查询结果如下:

{"_id": "1","price":{"vip":8}
}

对于联表查询,副表的数据嵌入到了主表的关联字段下面,此时在filed里通过{}来定义副表字段。比如之前联表查询章节举过的例子,book表和order表联表查询:

// 联表查询
db.collection('order,book') // 注意collection方法内需要传入所有用到的表名,用逗号分隔,主表需要放在第一位.field('book_id{title,author},quantity') // 这里联表查询book表返回book表内的title、book表内的author、order表内的quantity.get()

不使用{}过滤副表字段

此写法于2021年4月28日起支持

field方法内可以不使用{}进行副表字段过滤,以上面示例为例可以写为

const db = uniCloud.database()
db.collection('order,book').where('book_id.title == "三国演义"').field('book_id.title,book_id.author,quantity as order_quantity') // book_id.title、book_id.author为副表字段,使用别名时效果和上一个示例不同,请见下方说明.orderBy('order_quantity desc') // 按照order_quantity降序排列.get().then(res => {console.log(res);}).catch(err => {console.error(err)})

字段别名as

2020-11-20起JQL支持字段别名,主要用于在前端需要的字段名和数据库字段名称不一致的情况下对字段进行重命名。

用法形如:author as book_author,意思是将数据库的author字段重命名为book_author。

仍以上面的order表和book表为例

// 客户端联表查询
const db = uniCloud.database()
db.collection('book').where('title == "三国演义"').field('title as book_title,author as book_author').get().then(res => {console.log(res);}).catch(err => {console.error(err)})

上述查询返回结果如下

{"code": "","message": "","data": [{"_id": "3","book_author": "罗贯中","book_title": "三国演义"}]
}

_id是比较特殊的字段,如果对_id设置别名会同时返回_id和设置的别名字段

注意

  • as后面的别名,不可以和表schema中已经存在的字段重名
  • mongoDB查询指令中,上一阶段处理完毕将结果输出到下一阶段。在上面的例子中表现为where中使用的是原名,orderBy中使用的是别名
  • 目前不支持对联表查询的关联字段使用别名,即上述示例中的book_id不可设置别名

限制查询记录的条数limit

使用limit方法,可以查询有限条数的数据记录。

比如查询销量top10的书籍,或者查价格最高的一本书。

// 这以上面的book表数据为例,查价格最高的一本书db.collection('book').orderBy('price desc').limit(1).get()

limit默认值是100,即不设置的情况下,默认返回100条数据。limit最大值为1000。

一般情况下不应该给前端一次性返回过多数据,数据库查询也慢、网络返回也慢。可以通过分页的方式分批返回数据。

在查询的result里,有一个affectedDocs。但affectedDocs和limit略有区别。affectedDocs小于等于limit。

比如book表里只有2本书,limit虽然设了10,但查询结果只能返回2条记录,affectedDocs为2。

只查一条记录getone

使用JQL的API方式时,可以在get方法内传入参数getOne:true来返回一条数据。

getOne其实等价于上一节的limit(1)。

一般getOne和orderBy搭配。

// 这以上面的book表数据为例
const db = uniCloud.database()db.collection('book').where({title: '西游记'}).get({getOne:true}).then(res => {console.log(res);}).catch(err => {console.error(err)})

返回结果为

{"code": "","message": "","data": {"_id": "1","title": "西游记","author": "吴承恩"}
}

 

这篇关于uniCloud ---- JQL语法 连表查询的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/657814

相关文章

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优

mysql表操作与查询功能详解

《mysql表操作与查询功能详解》本文系统讲解MySQL表操作与查询,涵盖创建、修改、复制表语法,基本查询结构及WHERE、GROUPBY等子句,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随... 目录01.表的操作1.1表操作概览1.2创建表1.3修改表1.4复制表02.基本查询操作2.1 SE

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

XML重复查询一条Sql语句的解决方法

《XML重复查询一条Sql语句的解决方法》文章分析了XML重复查询与日志失效问题,指出因DTO缺少@Data注解导致日志无法格式化、空指针风险及参数穿透,进而引发性能灾难,解决方案为在Controll... 目录一、核心问题:从SQL重复执行到日志失效二、根因剖析:DTO断裂引发的级联故障三、解决方案:修复

mysql查询使用_rowid虚拟列的示例

《mysql查询使用_rowid虚拟列的示例》MySQL中,_rowid是InnoDB虚拟列,用于无主键表的行ID查询,若存在主键或唯一列,则指向其,否则使用隐藏ID(不稳定),推荐使用ROW_NUM... 目录1. 基本查询(适用于没有主键的表)2. 检查表是否支持 _rowid3. 注意事项4. 最佳实

MySQL存储过程之循环遍历查询的结果集详解

《MySQL存储过程之循环遍历查询的结果集详解》:本文主要介绍MySQL存储过程之循环遍历查询的结果集,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言1. 表结构2. 存储过程3. 关于存储过程的SQL补充总结前言近来碰到这样一个问题:在生产上导入的数据发现

MySQL JSON 查询中的对象与数组技巧及查询示例

《MySQLJSON查询中的对象与数组技巧及查询示例》MySQL中JSON对象和JSON数组查询的详细介绍及带有WHERE条件的查询示例,本文给大家介绍的非常详细,mysqljson查询示例相关知... 目录jsON 对象查询1. JSON_CONTAINS2. JSON_EXTRACT3. JSON_TA

MYSQL查询结果实现发送给客户端

《MYSQL查询结果实现发送给客户端》:本文主要介绍MYSQL查询结果实现发送给客户端方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql取数据和发数据的流程(边读边发)Sending to clientSending DataLRU(Least Rec

MySQL复杂SQL之多表联查/子查询详细介绍(最新整理)

《MySQL复杂SQL之多表联查/子查询详细介绍(最新整理)》掌握多表联查(INNERJOIN,LEFTJOIN,RIGHTJOIN,FULLJOIN)和子查询(标量、列、行、表子查询、相关/非相关、... 目录第一部分:多表联查 (JOIN Operations)1. 连接的类型 (JOIN Types)