unicloud-db组件
目录
[TOC]
unicloud-db组件简介
<unicloud-db> 组件是一个数据库查询组件,它是对 clientDB 的js库的再封装。
前端通过组件方式直接获取uniCloud的云端数据库中的数据,并绑定在界面上进行渲染。
在传统开发中,开发者需要在前端定义data、通过request联网获取接口数据、然后赋值给data。同时后端还需要写接口来查库和反馈数据。
有了 <unicloud-db> 组件, 上述工作只需要1行代码 !写组件,设组件的属性,在属性中指定要查什么表、哪些字段、以及查询条件,就OK了!
HBuilderX中敲下 udb 代码块,得到如下代码,然后通过collection属性指定要查询表“table1”,通过field属性指定要查询字段“field1”,并且在where属性中指定查询id为1的数据。查询结果data就可以直接渲染在界面上。
<unicloud-db v-slot:default="{data, loading, error, options}" collection="table1" field="field1" :getone="true" where="id=='1'">
<view>
{{ data}}
</view>
</unicloud-db>
<unicloud-db> 组件尤其适用于列表、详情等展示类页面。开发效率可以大幅度的提升。
<unicloud-db> 组件的查询语法是 jql ,这是一种比sql语句和nosql语法更简洁、更符合js开发者习惯的查询语法。没学过sql或nosql的前端,也可以轻松掌握。 jql详见
<unicloud-db> 组件不仅支持查询。还自带了add、remove、update方法,见下文方法章节
属性
| 属性 | 类型 | 描述 | ||
|---|---|---|---|---|
| v-slot:default | 查询状态(失败、联网中)及结果(data) | |||
| ref | string | vue组件引用标记 | ||
| spaceInfo | Object | 服务空间信息,新增于 HBuilderX 3.2.11 。同uniCloud.init参数,参考: uniCloud.init | ||
| collection | string | 表名。支持输入多个表名,用 , 分割,自 HBuilderX 3.2.6 起也支持传入tempCollection组成的数组 | ||
| field | string | 指定要查询的字段,多个字段用 , 分割。不写本属性,即表示查询所有字段。支持用 oldname as newname方式对返回字段重命名 | ||
| where | string | 查询条件,对记录进行过滤。 见下 | ||
| orderby | string | 排序字段及正序倒序设置 | ||
| foreign-key | String | 手动指定使用的关联关系,HBuilderX 3.1.10+ 详情 | ||
| page-data | String | 分页策略选择。值为 add 代表下一页的数据追加到之前的数据中,常用于滚动到底加载下一页;值为 replace 时则替换当前data数据,常用于PC式交互,列表底部有页码分页按钮,默认值为 add | ||
| page-current | Number | 当前页 | ||
| page-size | Number | 每页数据数量 | ||
| getcount | Boolean | 是否查询总数据条数,默认 false ,需要分页模式时指定为 true | ||
| getone | Boolean | 指定查询结果是否仅返回数组第一条数据,默认 false。在false情况下返回的是数组,即便只有一条结果,也需要[0]的方式获取。在值为 true 时,直接返回结果数据,少一层数组,一般用于非列表页,比如详情页 | ||
| action | string | 云端执行数据库查询的前或后,触发某个action函数操作,进行预处理或后处理, 详情 。场景:前端无权操作的数据,比如阅读数+1 | ||
| manual | Boolean | 已过时,使用 loadtime 替代 是否手动加载数据,默认为 false,页面onready时自动联网加载数据。如果设为 true,则需要自行指定时机通过方法 this.$refs.udb.loadData() 来触发联网,其中的 udb 指组件的ref值。一般onLoad因时机太早取不到this.$refs.udb,在onReady里可以取到 | ||
| gettree | Boolean | 是否查询树状结构数据,HBuilderX 3.0.5+ 详情 | ||
| startwith | String | gettree的第一层级条件,此初始条件可以省略,不传startWith时默认从最顶级开始查询,HBuilderX 3.0.5+ | ||
| limitlevel | Number | gettree查询返回的树的最大层级。超过设定层级的节点不会返回。默认10级,最大15,最小1,HBuilderX 3.0.5+ | ||
| groupby | String | 对数据进行分组,HBuilderX 3.1.0+ | ||
| group-field | String | 对数据进行分组统计 | ||
| distinct | Boolean | 是否对数据查询结果中重复的记录进行去重,默认值false,HBuilderX 3.1.0+ | ||
| loadtime | String | 加载数据时机,默认auto,可选值 auto | onready | manual, 详情 HBuilderX3.1.10+ |
| ssr-key | String | 详情 HBuilderX 3.4.11+ | ||
| @load | EventHandle | 成功回调。联网返回结果后,若希望先修改下数据再渲染界面,则在本方法里对data进行修改 | ||
| @error | EventHandle | 失败回调 |
TODO:暂不支持in子查询功能。后续会补充
注意: page-current/page-size 改变不重置数据( page-data="replace" ) 和 ( loadtime="manual" ) 除外, collection/action/field/getcount/orderby/where 改变后清空已有数据
示例
比如云数据库有个user的表,里面有字段id、name,查询id=1的数据,那么写法如下:
注意下面示例使用了getone会返回一条对象形式的data,如不使用getone,data将会是数组形式,即多一层
<template>
<view>
<unicloud-db v-slot:default="{data, loading, error, options}" collection="user" field="name" :getone="true" where="id=='1'">
<view>
{{ data.name}}
</view>
</unicloud-db>
</view>
</template>
注意:除非使用admin账户登录操作,否则需要在 uniCloud 控制台对要查询的表增加 Schema 权限配置。至少配置读取权限,否则无权在前端查询 ,详见 DB Schema
v-slot:default
<unicloud-db v-slot:default="{data, pagination, loading, hasMore, error, options}"></unicloud-db>
| 属性 | 类型 | 描述 | |
|---|---|---|---|
| data | Array | Object | 查询结果,默认值为 Array , 当 getone 指定为 true 时,值为数组中第一条数据,类型为 Object ,减少了一层 |
| pagination | Object | 分页属性 | |
| loading | Boolean | 查询中的状态。可根据此状态,在template中通过v-if显示等待内容,如 <view v-if="loading">加载中...</view> | |
| hasMore | Boolean | 是否有更多数据。可根据此状态,在template中通过v-if显示没有更多数据了,如 <uni-load-more v-if="!hasMore" status="noMore"></uni-load-more> , <uni-load-more> 详情 uni-load-more 加载更多 - DCloud 插件市场 | |
| error | Object | 查询错误。可根据此状态,在template中通过v-if显示等待内容,如 <view v-if="error">加载错误</view> | |
| options | Object | 在小程序中,插槽不能访问外面的数据,需通过此参数传递, 不支持传递函数 |
提示:如果不指定分页模式, data 为多次查询的集合
状态示例:
<unicloud-db v-slot:default="{data, loading, error, options}" collection="user">
<view v-if="error">{{error.message}}</view>
<view v-else-if="loading">正在加载...</view>
<view v-else>
{{data}}
</view>
</unicloud-db>
collection
collection有以下几种形式
单个collection字符串
<unicloud-db v-slot:default="{data, loading, error, options}" collection="user">
<view v-if="error">{{error.message}}</view>
<view v-else-if="loading">正在加载...</view>
<view v-else>
{{data}}
</view>
</unicloud-db>
多个collection字符串拼接
用于联表查询,注意主表副表之间需要在schema内以foreignKey关联(副表支持多个)。如下示例以book作为主表,关联author表进行查询,在book表的schema内设置author_id字段指向author表
<unicloud-db v-slot:default="{data, loading, error, options}" collection="book,author">
<view v-if="error">{{error.message}}</view>
<view v-else-if="loading">正在加载...</view>
<view v-else>
{{data}}
</view>
</unicloud-db>
多个临时表组成的数组
同样用于联表查询,但是与直接拼接多个字符串的方式不同,可以先对主表进行处理再关联。和直接使用多个表名字符串拼接相比,在主表数据量大的情况下性能有明显提升
<template>
<unicloud-db v-slot:default="{data, loading, error, options}" :collection="colList">
<view v-if="error">{{error.message}}</view>
<view v-else-if="loading">正在加载...</view>
<view v-else>
{{data}}
</view>
</unicloud-db>
</template>
<script>
const db = uniCloud.database()
export default {
data() {
return {
colList: [
db.collection('book').where('name == "水浒传"').getTemp(),
db.collection('author').getTemp()
]
}
},
onReady() {},
methods: {}
}
</script>
where
where中指定要查询的条件。比如只查询某个字段的值符合一定条件的记录。
组件的where属性,与clientDB的JS API是一致的,且内容较多,所以详见js API中相关 jql 文档: 详情
但组件与js API有一个差别,就是组件的属性中若使用js中的变量,需额外注意。
例如查询uni-id-users表,字段username的值由js变量指定,有如下几种方式:
方式1. 使用模板字符串,用${}包裹变量
<template>
<view>
<unicloud-db collection="uni-id-users" :where="`username=='${tempstr}'`"></unicloud-db>
</view>
</template>
<script>
export default {
data() {
return {
tempstr: '123'
}
}
}
</script>
方式2. 不在属性中写,而在js中拼接字符串
<template>
<view>
<unicloud-db ref="udb" collection="uni-id-users" :where="sWhere" loadtime="manual"></unicloud-db>
</view>
</template>
<script>
export default {
data() {
return {
tempstr: '123',
sWhere: ''
}
}
onLoad() {
this.sWhere = "id=='" + this.tempstr + "'"
// 组件上配置了 loadtime = "manual", 这里需要手动加载数据
this.$nextTick(() => {
this.$refs.udb.loadData()
})
}
}
</script>
多条件查询示例:
方式1. 使用模板字符串,用${}包裹变量
<template>
<view>
<unicloud-db ref="udb" collection="uni-id-users" where="`id==${this.tempstr} && create_time > 1613960340000`"></unicloud-db>
</view>
</template>
<script>
export default {
data() {
return {
tempstr: '123'
}
}
}
</script>
方式2. 使用js拼接字符串
<template>
<view>
<unicloud-db ref="udb" collection="uni-id-users" :where="sWhere" loadtime="manual"></unicloud-db>
</view>
</template>
<script>
export default {
data() {
return {
tempstr: '123',
sWhere: ''
}
}
onLoad() {
// id = this.tempstr 且 create_time > 1613960340000
this.sWhere = "id=='" + this.tempstr + "' && create_time > 1613960340000"
// id = this.tempstr 或 name != null
// this.sWhere = "id=='" + this.tempstr + "' || name != null"
// 组件上配置了 loadtime = "manual", 这里需要手动加载数据
this.$nextTick(() => {
this.$refs.udb.loadData()
})
}
}
</script>
上述示例使用的是==比较符,如需进行模糊搜索,则使用正则表达式。插件市场提供了完整的云端一体搜索模板,搜索类页面无需自行开发,可直接使用。 详见
使用正则模糊查询示例:
<template>
<view class="content">
<input @input="onKeyInput" placeholder="请输入搜索值" />
<unicloud-db v-slot:default="{data, loading, error, options}" collection="goods" :where="where">
<view v-if="error">{{error.message}}</view>
<view v-else>
</view>
</unicloud-db>
</view>
</template>
<script>
export default {
data() {
return {
searchVal: ''
}
},
computed: {
where() {
return `${new RegExp(this.searchVal, 'i')}.test(name)` // 使用计算属性得到完整where
}
},
methods: {
onKeyInput(e) {
// 实际开发中这里应该还有防抖或者节流操作,这里不做演示
this.searchVal = e.target.value
}
}
}
</script>
再次强调,where条件内容较多,组件和api用法相同,完整的where条件文档在api文档中,另见: JQL文档
orderby
格式为 字段名 空格 asc (升序)/ desc (降序),多个字段用 , 分割,优先级为字段顺序
单字段排序,示例代码
<unicloud-db orderby="createTime desc"></unicloud-db>
多字段排序,示例代码
<unicloud-db orderby="createTime1 asc,createTime2 desc"></unicloud-db>
联表查询
联表查询有以下两种写法,对于数据量稍大的表推荐使用多个临时表组成的数组作为collection,可以在主表的getTemp内先进行过滤减小联表时的性能消耗。
更多关于联表查询的内容请参考: JQL联表查询
多个collection字符串拼接
用于联表查询,注意主表副表之间需要在schema内以foreignKey关联(副表支持多个)。如下示例以book作为主表,关联author表进行查询,在book表的schema内设置author_id字段指向author表
<unicloud-db v-slot:default="{data, loading, error, options}" collection="book,author">
<view v-if="error">{{error.message}}</view>
<view v-else-if="loading">正在加载...</view>
<view v-else>
{{data}}
</view>
</unicloud-db>
多个临时表组成的数组
同样用于联表查询,但是与直接拼接多个字符串的方式不同,可以先对主表进行处理再关联。和直接使用多个表名字符串拼接相比,在主表数据量大的情况下性能有明显提升
<template>
<unicloud-db v-slot:default="{data, loading, error, options}" :collection="colList">
<view v-if="error">{{error.message}}</view>
<view v-else-if="loading">正在加载...</view>
<view v-else>
{{data}}
</view>
</unicloud-db>
</template>
<script>
const db = uniCloud.database()
export default {
data() {
return {
colList: [
db.collection('book').where('name == "水浒传"').getTemp(),
db.collection('author').getTemp()
]
}
},
onReady() {},
methods: {}
}
</script>
loadtime
| 值 | 类型 | 描述 |
|---|---|---|
| auto | String | 页面就绪后或属性变化后加载数据,默认为auto |
| onready | String | 页面就绪后不自动加载数据,属性变化后加载。适合在onready中接收上个页面的参数作为where条件时。 |
| manual | String | 手动模式,不自动加载数据。如果涉及到分页,需要先手动修改当前页,在调用加载数据 |
方法:loadData
当 <unicloud-db> 组件的 manual 属性设为 true 时,不会在页面初始化时联网查询数据,此时需要通过本方法在需要的时候手动加载数据。
this.$refs.udb.loadData() //udb为unicloud-db组件的ref属性值
一般onLoad因时机太早取不到this.$refs.udb,在onReady里可以取到。
举例常见场景,页面pagea在url中获取参数id,然后加载数据
请求地址:/pages/pagea?id=123
pagea.vue源码:
<template>
<view>
<unicloud-db ref="udb" collection="table1" :where="where" v-slot:default="{data,pagination,loading,error,options}" :options="options" manual>
{{data}}
</unicloud-db>
</view>
</template>
<script>
export default {
data() {
return {
_id:'',
where: ''
}
},
onLoad(e) {
const id = e.id
if (id) {
this._id = id
this.where = "_id == '" + this._id + "'"
}
else {
uni.showModal({
content:"页面参数错误",
showCancel:false
})
}
},
onReady() {
if (this._id) {
this.$refs.udb.loadData()
}
}
}
</script>
下拉刷新示例
this.$refs.udb.loadData({clear: true}, callback) ,
可选参数 clear: true ,是否清空数据和分页信息, true 表示清空,默认 false
callback 是回调函数,加载数据完成后触发(即使加载失败)
<script>
export default {
data() {
return {
}
},
// 页面生命周期,下拉刷新后触发
onPullDownRefresh() {
this.$refs.udb.loadData({
clear: true
}, () => {
// 停止下拉刷新
uni.stopPullDownRefresh()
})
}
}
</script>
方法:remove
语法
this.$refs.udb.remove(id, options)
udb为unicloud-db组件的ref属性值
必选参数 id
| 属性 | 类型 | 默认值 | 描述 | |
|---|---|---|---|---|
| id | string | Array | 传入数据库的_id |
可选参数 options
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| action | string | 云端执行数据库查询的前或后,触发某个action函数操作,进行预处理或后处理,详情。场景:前端无权操作的数据,比如阅读数+1 | |
| confirmTitle | string | 提示 | 删除确认框标题 |
| confirmContent | string | 是否删除该数据 | 删除确认框提示 |
| needConfirm | boolean | true | 控制是否有弹出框,HBuilderX 3.1.5+ |
| needLoading | boolean | true | 是否显示Loading,HBuilderX 3.1.5+ |
| loadingTitle | string | '' | 显示loading的标题,HBuilderX 3.1.5+ |
| success | function | 删除成功后的回调 | |
| fail | function | 删除失败后的回调 | |
| complete | function | 完成后的回调 |
在列表页面,如果想删除一个item,原本要做很多事:
- 弹出删除确认框
- 弹出loading
- 调用clientDB的js api删除云端数据
- 接收云端删除结果,如果成功则关闭loading
- 进一步删除列表的data中对应的item,自动刷新页面
为减少重复开发, unicloud-db组件 提供了remove方法,在列表渲染时绑定好index,直接调用remove方法即可一行代码完成上述5步。
首先在列表生成的时候给删除按钮绑定好id:
<unicloud-db ref="udb" :collection="collectionName" v-slot:default="{data,pagination,loading,error}">
<uni-table :loading="loading" :emptyText="error.message || '没有更多数据'" border stripe >
<uni-tr>
<uni-th>用户名</uni-th>
<uni-th>操作</uni-th>
</uni-tr>
<uni-tr v-for="(item,index) in data" :key="index">
<uni-th>{{item.username}}</uni-th>
<uni-td>
<view>
<button @click="confirmDelete(item._id)" type="warn">删除</button>
</view>
</uni-td>
</uni-tr>
</uni-table>
</unicloud-db>
然后confirmDelete方法里面只有一行代码:
confirmDelete(id) {
this.$refs.udb.remove(id)
}
clientDB 组件的remove方法的参数只支持传入数据库的_id进行删除,不支持其他where条件删除。
参数传入的_id支持单个,也支持多个,即可以批量删除。多个id的格式是:
this.$refs.udb.remove(["5f921826cf447a000151b16d", "5f9dee1ff10d2400016f01a4"])
在uniCloud的web控制台的 DB Schema 界面,可自助生成数据表的admin管理插件,其中有多行数据批选批删示例。
完整实例,第二个是可选参数。
var ids = ["5f921826cf447a000151b16d", "5f9dee1ff10d2400016f01a4"]
this.$refs.udb.remove(ids, {
action: '', // 删除前后的动作
confirmTitle: '提示', // 确认框标题
confirmContent: '是否删除该数据', // 确认框内容
success: (res) => { // 删除成功后的回调
const { code, message } = res
},
fail: (err) => { // 删除失败后的回调
const { message } = err
},
complete: () => { // 完成后的回调
}
})
方法:add
语法
this.$refs.udb.add(value, options)
udb为unicloud-db组件的ref属性值
必选参数 value
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| value | Object | 新增数据 |
可选参数 options
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| action | string | 云端执行数据库查询的前或后,触发某个action函数操作,进行预处理或后处理,详情。HBuilder 3.1.0+ | |
| showToast | boolean | true | 是否显示更新成功后的提示框 |
| toastTitle | string | 新增成功 | 新增成功后的toast提示 |
| needLoading | boolean | true | 是否显示Loading,HBuilderX 3.1.5+ |
| loadingTitle | string | '' | 显示loading的标题,HBuilderX 3.1.5+ |
| success | function | 新增成功后的回调 | |
| fail | function | 新增失败后的回调 | |
| complete | function | 完成后的回调 |
<unicloud-db ref="udb" :collection="collectionName" v-slot:default="{data,pagination,loading,error}">
</unicloud-db>
this.$refs.udb.add(value)
完整实例
this.$refs.udb.add(value, {
toastTitle: '新增成功', // toast提示语
success: (res) => { // 新增成功后的回调
const { code, message } = res
},
fail: (err) => { // 新增失败后的回调
const { message } = err
},
complete: () => { // 完成后的回调
}
})
方法:refresh
清空并重新加载当前页面数据
this.$refs.udb.refresh() //udb为unicloud-db组件的ref属性值
方法:dataList
在js中,获取 <unicloud-db> 组件的data的方法如下:
console.log(this.$refs.udb.dataList);
如果修改了dataList的值,组件渲染的界面也会同步变化。
但是在浏览器控制台里无法使用this来打印查看数据,为此特别新增了 unidev.clientDB.data 方法以优化调试体验。
H5平台,开发模式下浏览器控制台输入 unidev.clientDB.data ,可查看组件内部数据,多个组件通过索引查看 unidev.clientDB.data[0]
扩展:jql语句内云端环境变量
| 参数名 | 说明 |
|---|---|
| $cloudEnv_uid | 用户uid,依赖uni-id |
| $cloudEnv_now | 服务器时间戳 |
| $cloudEnv_clientIP | 当前客户端IP |
在字符串内使用
db.collection('user').where('_id==$cloudEnv_uid').get()
在对象内使用
db.collection('user').where({
_id: db.getCloudEnv('$cloudEnv_uid')
}).get()
注意
- 这些变量使用时并非直接获取对应的值,而是生成一个标记,在云端执行数据库操作时再将这个标记替换为实际的值