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

相关文章

MyBatis分页查询实战案例完整流程

《MyBatis分页查询实战案例完整流程》MyBatis是一个强大的Java持久层框架,支持自定义SQL和高级映射,本案例以员工工资信息管理为例,详细讲解如何在IDEA中使用MyBatis结合Page... 目录1. MyBATis框架简介2. 分页查询原理与应用场景2.1 分页查询的基本原理2.1.1 分

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

MySQL中查询和展示LONGBLOB类型数据的技巧总结

《MySQL中查询和展示LONGBLOB类型数据的技巧总结》在MySQL中LONGBLOB是一种二进制大对象(BLOB)数据类型,用于存储大量的二进制数据,:本文主要介绍MySQL中查询和展示LO... 目录前言1. 查询 LONGBLOB 数据的大小2. 查询并展示 LONGBLOB 数据2.1 转换为十

使用SpringBoot+InfluxDB实现高效数据存储与查询

《使用SpringBoot+InfluxDB实现高效数据存储与查询》InfluxDB是一个开源的时间序列数据库,特别适合处理带有时间戳的监控数据、指标数据等,下面详细介绍如何在SpringBoot项目... 目录1、项目介绍2、 InfluxDB 介绍3、Spring Boot 配置 InfluxDB4、I

Go语言使用Gin处理路由参数和查询参数

《Go语言使用Gin处理路由参数和查询参数》在WebAPI开发中,处理路由参数(PathParameter)和查询参数(QueryParameter)是非常常见的需求,下面我们就来看看Go语言... 目录一、路由参数 vs 查询参数二、Gin 获取路由参数和查询参数三、示例代码四、运行与测试1. 测试编程路

MySQL 数据库表与查询操作实战案例

《MySQL数据库表与查询操作实战案例》本文将通过实际案例,详细介绍MySQL中数据库表的设计、数据插入以及常用的查询操作,帮助初学者快速上手,感兴趣的朋友跟随小编一起看看吧... 目录mysql 数据库表操作与查询实战案例项目一:产品相关数据库设计与创建一、数据库及表结构设计二、数据库与表的创建项目二:员

Linux查询服务器 IP 地址的命令详解

《Linux查询服务器IP地址的命令详解》在服务器管理和网络运维中,快速准确地获取服务器的IP地址是一项基本但至关重要的技能,下面我们来看看Linux中查询服务器IP的相关命令使用吧... 目录一、hostname 命令:简单高效的 IP 查询工具命令详解实际应用技巧注意事项二、ip 命令:新一代网络配置全

Linux查询服务器系统版本号的多种方法

《Linux查询服务器系统版本号的多种方法》在Linux系统管理和维护工作中,了解当前操作系统的版本信息是最基础也是最重要的操作之一,系统版本不仅关系到软件兼容性、安全更新策略,还直接影响到故障排查和... 目录一、引言:系统版本查询的重要性二、基础命令解析:cat /etc/Centos-release详

MySQL慢查询工具的使用小结

《MySQL慢查询工具的使用小结》使用MySQL的慢查询工具可以帮助开发者识别和优化性能不佳的SQL查询,本文就来介绍一下MySQL的慢查询工具,具有一定的参考价值,感兴趣的可以了解一下... 目录一、启用慢查询日志1.1 编辑mysql配置文件1.2 重启MySQL服务二、配置动态参数(可选)三、分析慢查

MyBatis流式查询两种实现方式

《MyBatis流式查询两种实现方式》本文详解MyBatis流式查询,通过ResultHandler和Cursor实现边读边处理,避免内存溢出,ResultHandler逐条回调,Cursor支持迭代... 目录MyBATis 流式查询详解:ResultHandler 与 Cursor1. 什么是流式查询?