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": "吴承恩"
  }
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/356042.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue3 el-pagination 将组件中英文‘goto’ 修改 为 中文到‘第几’

效果如图&#xff1a; 要求&#xff1a;将英文中Go to 改为到第几 操作如下&#xff1a; <template><div class"paging"><el-config-provider :locale"zhCn"> // 注意&#xff1a;这是重要部分<el-pagination //分页组件根据官…

解锁创意无限:Adobe Photoshop 2023(PS2023)引领设计革命

Adobe Photoshop 2023 (PS2023)&#xff0c;作为图像处理软件的翘楚&#xff0c;以其卓越的性能和无限的可能性&#xff0c;继续引领着数字创意设计的潮流。对于设计师、摄影师、艺术家以及那些对视觉效果有高要求的人们来说&#xff0c;PS2023无疑是他们的必备工具。 在PS202…

OpenHarmony—ArkTS限制throw语句中表达式的类型

规则&#xff1a;arkts-limited-throw 级别&#xff1a;错误 ArkTS只支持抛出Error类或其派生类的实例。禁止抛出其他类型&#xff08;例如number或string&#xff09;的数据。 TypeScript throw 4; throw ; throw new Error();ArkTS throw new Error();限制省略函数返回类…

SpringBoot + Mybatis 快速入门实战

一.创建Spring项目 出现报错的话&#xff0c;换一个jdk创建&#xff0c;一般java 8 选择Spring Web 测试一下 默认端口8080&#xff0c;但是Vue也需要8080&#xff0c;因此&#xff0c;后端设置一个端口3000 再次测试&#xff0c;成功 此处&#xff0c;如何kill一个端口占…

Spring Cloud + Vue前后端分离-第14章 项目优化

源代码在GitHub - 629y/course: Spring Cloud Vue前后端分离-在线课程 Spring Cloud Vue前后端分离-第14章 项目优化 14-1 项目初始化 1.增加readme.md&#xff0c;添加项目介绍 2.修改初始化sql README.md readme.md是用来写一些项目描述信息&#xff0c;git远程仓库可…

数字图像处理(实践篇)三十六 OpenCV-Python 使用ORB和BFmatcher对两个输入图像的关键点进行匹配实践

目录 一 涉及的函数 二 实践 ORB(Oriented FAST and Rotated BRIEF)是一种特征点检测和描述算法,它结合了FAST关键点检测和BRIEF描述子。ORB算法具有以下优势: ①实时性:能够在实时应用中进行快速的特征点检测和描述。 ②

SpringBoot,TDengine时序数据库,实现物联网,车联网大批量数据更新最佳实践。

简介 TDengine 是一款专为物联网、工业互联网等场景设计并优化的大数据平台&#xff0c;它能安全高效地将大量设备、数据采集器每天产生的高达 TB 甚至 PB 级的数据进行汇聚、存储、分析和分发&#xff0c;对业务运行状态进行实时监测、预警&#xff0c;提供实时的商业洞察。其…

【C/C++】02_希尔排序

希尔排序虽然是直接插入排序的升级版本&#xff0c;和插入排序有着相同的特性&#xff0c;即原始数组有序度越高则算法的时间复杂度越低&#xff08;预排序机制&#xff09;&#xff0c;但是是不稳定排序算法。 为了降低算法的时间复杂度&#xff0c;所以我们需要在排序之前尽…

数据结构OJ题——二叉树前序、中序遍历非递归实现(Java版)

二叉树前序、中序遍历非递归实现 前序非递归遍历实现中序非递归遍历实现 前序非递归遍历实现 题目&#xff1a; 二叉树前序遍历非递归实现 总体思路&#xff1a;用非递归的方式模拟递归遍历。 以下图为例&#xff1a; 图示详解&#xff1a; 代码实现&#xff1a; /*** Defi…

promethues

1、定义&#xff1a;promethues是一个开源的系统监控以及报警系统&#xff0c;整合zabbix的功能&#xff08;监控系统、网络、设备&#xff09;&#xff0c;promethues可以兼容网络、设备、容器监控、告警系统。因为其与k8s是一个项目基金开发出来的产品&#xff0c;天生匹配k8…

汽车网络安全管理体系框架与评价-汽车网络安全管理体系评价

当前 &#xff0c; 随若汽车联网产品渗透率、 智能传感设备搭载率的提升&#xff0c; 以及汽车与通信、互联网等行业的融合创新发展&#xff0c; 汽车行业面临愈发严峻的网络安全风险&#xff0c; 对消费者人身财产安全、 社会安全乃至国家安全产生威胁&#xff0c; 是产业发展…

【Spark系列1】DAG中Stage和Task的划分全流程

一、整体流程 每个Aciton操作会创建一个JOB&#xff0c;JOB会提交给DAGScheduler&#xff0c;DAGScheduler根据RDD依赖的关系划分为多个Stage&#xff0c;每个Stage又会创建多个TaskSet&#xff0c;每个TaskSet包含多个Task&#xff0c;这个Task就是每个分区的并行计算的任务。…

头戴式耳机哪个牌子音质好?2024音质超好的百元头戴式耳机品牌推荐

在当今数字化的时代&#xff0c;音乐已成为我们生活中不可或缺的一部分&#xff0c;而头戴式耳机因其优质的音效和舒适的佩戴感&#xff0c;成为了许多音乐爱好者的首选&#xff0c;在众多品牌中&#xff0c;究竟哪个牌子的头戴式耳机音质最好呢&#xff1f;今天我就来给大家推…

echarts坐标轴文字样式

https://echarts.apache.org/zh/option.html#xAxis.nameTextStyle xAxis. nameTextStyle、 yAxis: {type: value,// max: -0.15,name: 沉降累计值/mm,nameTextStyle: {padding: [0, 0, 0, 10],color: #93B8E2,fontSize: 12,fontFamily: Alibaba-PuHuiTi-R},splitLine: {show:…

procmethues 二进制安装

pormethues是一个开源的系统监控以及报警系统。整合zabbix的功能&#xff0c;系统&#xff0c;网络&#xff0c;设备。 procmeteus可以兼容网络&#xff0c;设备。容器监控。告警系统。因为他和k8s是一个项目开发的产品&#xff0c;天生匹配k8s的原生系统。容器化和云原生服务…

【Java基础】JVM关闭回调函数(ShutdownHook)的应用场景

文章目录 一.ShutdownHook介绍二.ShutdownHook被调用场景三.ShutdownHook如何使用四.ShutdownHook实践 一.ShutdownHook介绍 ShutdownHook就是一个简单的 已初始化 但是 未启动 的 线程 。当虚拟机开始关闭时&#xff0c;它将会调用所有已注册ShutdownHook的回调函数&#xff0…

Gnuplot安装与配置

安装默认选项&#xff0c;下一步配置环境变量 找到系统环境变量&#xff0c;找到PATH 新建 浏览 将bin目录加进去 如图 再按winR&#xff0c;输入cmd打开终端&#xff0c;输入gnuplot&#xff0c;如果提示以下信息就可以绘图 如果要在Visual Studio中结合代码使用&#xff0c;需…

【局部自动数据增强】YOCO:将图片一分为二,各自增强后拼合为一

【自动数据增强】YOCO&#xff1a;将图片一分为二&#xff0c;各自增强后拼合为一 核心思想好在哪里&#xff1f;切哪里、切几次&#xff1f;何时用&#xff1f; 总结 核心思想 论文&#xff1a;https://arxiv.org/pdf/2201.12078.pdf 代码&#xff1a;https://github.com/Ju…

MySql的使用方法

一.什么是MySql MySql是一种数据库管理系统&#xff0c;是用来存储数据的&#xff0c;可以有效的管理数据&#xff0c;数据库的存储介质为硬盘和内存。 和文件相比&#xff0c;它具有以下优点&#xff1a; 文件存储数据是不安全的&#xff0c;且不方便数据的查找和管理&#xf…

Python网络拓扑库之mininet使用详解

概要 网络工程师、研究人员和开发人员需要进行各种网络实验和测试&#xff0c;以评估网络应用和协议的性能&#xff0c;以及解决网络问题。Python Mininet是一个功能强大的工具&#xff0c;它允许用户创建、配置和仿真复杂的网络拓扑&#xff0c;以满足各种实际应用场景。本文…