Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
DCloud
uni-app
提交
90830cc1
U
uni-app
项目概览
DCloud
/
uni-app
15 天 前同步成功
通知
702
Star
38703
Fork
3642
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
7
列表
看板
标记
里程碑
合并请求
1
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
uni-app
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
7
Issue
7
列表
看板
标记
里程碑
合并请求
1
合并请求
1
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
90830cc1
编写于
12月 27, 2020
作者:
W
wanganxp
提交者:
GitHub
12月 27, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Update clientdb.md
上级
af1fa4f6
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
225 addition
and
125 deletion
+225
-125
docs/uniCloud/clientdb.md
docs/uniCloud/clientdb.md
+225
-125
未找到文件。
docs/uniCloud/clientdb.md
浏览文件 @
90830cc1
...
...
@@ -8,7 +8,7 @@
1个应用开发的一半的工作量,就此直接省去。
当然使用
`clientDB`
需要扭转传统后台开发观念,不再编写
云函数
,直接在前端操作数据库。但是为了数据安全,需要在数据库上配置
`DB Schema`
。
当然使用
`clientDB`
需要扭转传统后台开发观念,不再编写
服务端代码
,直接在前端操作数据库。但是为了数据安全,需要在数据库上配置
`DB Schema`
。
在
`DB Schema`
中,配置数据操作的权限和字段值域校验规则,阻止前端不恰当的数据读写。详见:
[
DB Schema
](
https://uniapp.dcloud.net.cn/uniCloud/schema
)
...
...
@@ -23,14 +23,14 @@
## clientDB图解
![](
https://static-eefb4127-9f58-4963-a29b-42856d4205ee.bspapp.com/clientdb.jpg
)
`clientDB`
的前端
部分包括js API和
`<unicloud-db>`
组件两部分
。
`clientDB`
的前端
,有两种用法,可以用js API操作云数据库,也可以使用
`<unicloud-db>`
组件
。
js API可以执行所有数据库操作。
`<unicloud-db>`
组件是js API的再封装,进一步简化查询等常用数据库操作的代码量。
-
在HBuilderX 3.0+,
`<unicloud-db>`
组件已经内置,可以直接使用。文档另见:
[
<unicloud-db>组件
](
/uniCloud/unicloud-db
)
-
在HBuilderX 3.0以前的版本,使用该组件需要在插件市场单独引用
`<uni-clientDB>插件`
,另见:
[
https://ext.dcloud.net.cn/plugin?id=3256
](
https://ext.dcloud.net.cn/plugin?id=3256
)
以下文章重点介绍
`clientDB`
的js API。
组件的使用语法类似,但请单独查阅组件的文档
。
以下文章重点介绍
`clientDB`
的js API。
至于组件的用法,另见
[
文档
](
/uniCloud/unicloud-db
)
。
## clientDB前端API@jssdk
...
...
@@ -108,7 +108,7 @@ db.collection('list')
```
js
const
db
=
uniCloud
.
database
()
let
res
=
await
db
.
collection
(
'
table
'
).
where
({
user_id
:
db
.
env
.
uid
// 查询当前用户的数据
user_id
:
db
.
env
.
uid
// 查询当前用户的数据
。虽然代码编写在客户端,但环境变量会在云端运算
}).
get
()
```
...
...
@@ -116,7 +116,7 @@ let res = await db.collection('table').where({
`jql`
,全称javascript query language,是一种js方式操作数据库的语法规范。
`jql`
大幅降低了js工程师操作数据库的难度、大幅缩短开发代码量。并利用json数据库的嵌套特点,极大的简化了联表查询的复杂度。
`jql`
大幅降低了js工程师操作数据库的难度、大幅缩短开发代码量。并利用json数据库的嵌套特点,极大的简化了联表查询
和树查询
的复杂度。
#### jql的诞生背景
...
...
@@ -139,7 +139,7 @@ let res = await db.collection('table').where({
sql写法,对js工程师而言有学习成本,而且无法处理非关系型的MongoDB数据库,以及sql的联表查询inner join、left join也并不易于学习。
而nosql的写法,实在过于复杂。
而nosql的写法,实在过于复杂。
比如如下3个例子:
1.
运算符需要转码,
`>`
需要使用
`gt`
方法、
`==`
需要使用
`eq`
方法
...
...
@@ -645,173 +645,273 @@ const db = uniCloud.database()
}
```
### 查询树形
结构所有子节点
@gettree
### 查询树形
数据
@gettree
自3.0.3起,clientDB支持在get方法内传入getTree参数对包含父子关系的表查询返回树状结构数据。
HBuilderX 3.0.3+起,clientDB支持在get方法内传入getTree参数查询树状结构数据。(unicloud-db组件还未支持,目前只能通过js方式使用)
```
js
// get方法示例
get
({
getTree
:
{
limitLevel
:
10
,
// 最大查询层级(不包含当前层级),可以省略默认10级,最大15最小1
startWith
:
'
parent_code==null
'
// 第一层级条件,此初始条件可以省略,不传startWith时默认从最顶级开始查询
}
})
树形数据,在数据库里一般不会按照tree的层次来存储,因为按tree结构通过json对象的方式存储不同层级的数据,不利于对tree上的某个节点单独做增删改查。
一般存储树形数据,tree上的每个节点都是一条单独的数据表记录,然后通过类似parent_id来表达父子关系。
如部门的数据表,里面有2条数据,一条数据记录是“总部”,
`parent_id`
为空;另一条数据记录“一级部门A”,
`parent_id`
为总部的
`_id`
```
json
{
"_id"
:
"5fe77207974b6900018c6c9c"
,
"name"
:
"总部"
,
"parent_id"
:
""
,
}
```
```
json
{
"_id"
:
"5fe77232974b6900018c6cb1"
,
"name"
:
"一级部门A"
,
"parent_id"
:
"5fe77207974b6900018c6c9c"
,
}
```
以下面的表结构及数据为例
虽然存储格式是分条记录的,但查询反馈到前端的数据仍然需要是树形的。这种转换在过去比较复杂。
```
js
// test-tree 表结构
clientDB提供了一种简单、优雅的方案,在DB Schema里配置parentKey来表达父子关系,然后查询时声明使用Tree查询,就可以直接查出树形数据。
department部门表的schema中,将字段
`parent_id`
的"parentKey"设为"_id",即指定了数据之间的父子关系,如下:
```
json
{
"bsonType"
:
"object"
,
"
required
"
:
[],
"required"
:
[
"name"
],
"properties"
:
{
"
parent_code
"
:
{
"
bsonType
"
:
"
string
"
,
"
description
"
:
"
父级code
"
,
"
parentKey
"
:
"
code
"
,
// 指定父子关系为:如果数据库记录A的code和数据库记录B的parent_code相等,则A是B的父级。一个表内只能有一个父子关系
},
"
code
"
:
{
"
bsonType
"
:
"
string
"
,
"
description
"
:
"
当前code
},
"_id"
:
{
"description"
:
"ID,系统自动生成"
},
"name"
:
{
"
bsonType
"
:
"
string
"
,
"
description
"
:
"
名称
"
}
"bsonType"
:
"string"
,
"description"
:
"名称"
},
"parent_id"
:
{
"bsonType"
:
"string"
,
"description"
:
"父id"
,
"parentKey"
:
"_id"
,
//
指定父子关系为:如果数据库记录A的_id和数据库记录B的parent_id相等,则A是B的父级。
}
}
}
```
假设上述表有以下数据
parentKey字段将数据表不同记录的父子关系描述了出来。查询就可以直接写了。
```
js
{
name
:
'
p1
'
,
code
:
'
1
'
}
{
parent_code
:
'
1
'
,
name
:
'
c11
'
,
code
:
'
11
'
}
{
parent_code
:
'
1
'
,
name
:
'
c12
'
,
code
:
'
12
'
}
{
name
:
'
p2
'
,
code
:
'
2
'
}
{
parent_code
:
'
2
'
,
name
:
'
c21
'
,
code
:
'
21
'
}
{
parent_code
:
'
2
'
,
name
:
'
c22
'
,
code
:
'
22
'
}
```
注意一个表内只能有一个父子关系,即一个表的schema里只能配置一份parentKey。
schema里描述好后,查询就变的特别简单。
查询树形数据,分为 查询所有子节点 和 查询父级路径 这2种需求。
#### 查询所有子节点
以上面的表结构为例以下两种写法是等价的
指定符合条件的记录,然后查询它的所有子节点,并且可以指定层级,返回的结果是以符合条件的记录为一级节点的所有子节点数据,并以树形方式嵌套呈现。
只需要在clientDB的get方法中增加
`getTree`
参数,如下
```
js
// get方法示例
get
({
getTree
:
{
limitLevel
:
10
,
startWith
:
'
parent_code==null
'
limitLevel
:
10
,
// 最大查询层级(不包含当前层级),可以省略默认10级,最大15,最小1
startWith
:
"
parent_code==''
"
// 第一层级条件,此初始条件可以省略,不传startWith时默认从最顶级开始查询
}
})
```
get
({
getTree
:
true
})
完整的代码如下:
```
js
db
.
collection
(
"
department
"
).
get
({
getTree
:
{}
})
.
then
((
res
)
=>
{
const
resdata
=
res
.
result
.
data
console
.
log
(
"
resdata
"
,
resdata
);
}).
catch
((
err
)
=>
{
uni
.
showModal
({
content
:
err
.
message
||
'
请求服务失败
'
,
showCancel
:
false
})
}).
finally
(()
=>
{
})
```
如果要查询code为'1'的数据及其在树形结构所有的子节点,可以使用如下写法
查询的结果如下:
```
json
"data"
:
[{
"_id"
:
"5fe77207974b6900018c6c9c"
,
"name"
:
"总部"
,
"parent_id"
:
""
,
"children"
:
[{
"_id"
:
"5fe77232974b6900018c6cb1"
,
"name"
:
"一级部门A"
,
"parent_id"
:
"5fe77207974b6900018c6c9c"
,
"children"
:
[]
}]
}]
```
```
js
// 完整写法示例
const
res
=
await
db
.
collection
(
'
opendb-china-cities
'
)
.
field
(
'
name as text,code as value
'
)
.
get
({
getTree
:
{
startWith
:
'
code == "1"
'
}
})
// 查询结果
{
data
:
[{
text
:
'
p1
'
,
value
:
'
1
'
,
children
:[{
text
:
'
c11
'
,
value
:
'
11
'
,
children
:
[]
},{
text
:
'
c12
'
,
value
:
'
12
'
,
children
:
[]
}]
}]
}
可以看出,每个子节点,被嵌套在父节点的"children"下,这个"children"是一个固定的格式。
如果不指定getTree的参数,会把department表的所有数据都查出来,从总部开始到10级部门,以树形结构提供给客户端。
如果有多个总部,即多行记录的
`parent_id`
为空,则多个总部会分别作为一级节点,把它们下面的所有children一级一级拉出来。如下:
```
json
"data"
:
[
{
"_id"
:
"5fe77207974b6900018c6c9c"
,
"name"
:
"总部"
,
"parent_id"
:
""
,
"children"
:
[{
"_id"
:
"5fe77232974b6900018c6cb1"
,
"name"
:
"一级部门A"
,
"parent_id"
:
"5fe77207974b6900018c6c9c"
,
"children"
:
[]
}]
},
{
"_id"
:
"5fe778a10431ca0001c1e2f8"
,
"name"
:
"总部2"
,
"parent_id"
:
""
,
"children"
:
[{
"_id"
:
"5fe778e064635100013efbc2"
,
"name"
:
"总部2的一级部门B"
,
"parent_id"
:
"5fe778a10431ca0001c1e2f8"
,
"children"
:
[]
}]
}
]
```
如果觉得返回的
`parent_id`
字段多余,也可以指定
`.field("_id,name")`
,过滤掉该字段。
**getTree的参数limitLevel的说明**
limitLevel表示查询返回的树的最大层级。超过设定层级的节点不会返回。
-
limitLevel的默认值为10。
-
limitLevel的合法值域为1-15之间(包含1、15)。如果数据实际层级超过15层,请分层懒加载查询。
-
limitLevel为1,表示向下查一级子节点。假如数据库中有2级、3级部门,如果设limitLevel为1,且查询的是“总部”,那么返回数据包含“总部”和其下的一级部门。
**getTree的参数startWith的说明**
如果只需要查“总部”的子部门,不需要“总部2”,可以在where条件里指定(
`.where("name=='总部'")`
),也可以在startWith里指定(
`getTree: {"startWith":"name=='总部'"}`
)。
那么这2种指定方式的区别是什么呢?有的场景下,where条件可能用于描述其他查询条件,和以什么数据为根的描述冲突。此时就需要单独指定starWith。
startWith不填时,默认的条件是
`'parent_id==null||parent_id==""'`
,即schema配置parentKey的字段为null(即不存在)或值为空字符串时,这样的节点被默认视为根节点。
getTree一定会返回一个嵌套的树形数据,如果指定的查询条件没有子数据,查询会报错。
**大数据量的树形数据查询**
如果tree的数据量较大,则不建议一次性把所有的树形数据返回给客户端。建议分层查询,即懒加载。
比如地区选择的场景,全国的省市区数据量很大,一次性查询所有数据返回给客户端非常耗时和耗流量。可以先查省,然后根据选择的省再查市,以此类推。
**注意**
-
目前不支持使用getTree的同时使用其他联表查询语法
-
暂不支持使用getTree的同时使用联表查询
-
如果使用了where条件会对所有查询的节点生效
-
不可一次查询量特别大的数据,比如一次性加载所有的省市区。推荐在菜单、部门选择等小数据量的场景下使用
### 查询树形结构所有父节点@gettreepath
#### 查询树形结构父节点路径@gettreepath
getTree是查询子节点,而getTreePath,则是查询父节点。
自2020-12-26起,clientDB支持在
get方法内传入getTreePath参数对包含父子关系的表查询返回树状结构数据某节点路径。
get方法内传入getTreePath参数对包含父子关系的表查询返回树状结构数据某节点路径。
```
js
// get方法示例
get
({
getTreePath
:
{
limitLevel
:
10
,
// 最大查询层级(不包含当前层级),可以省略默认10级,最大15最小1
startWith
:
'
code=="22"
'
// 第一层级
条件,此初始条件不可以省略
limitLevel
:
10
,
// 最大查询层级(不包含当前层级),可以省略默认10级,最大15
,
最小1
startWith
:
'
name=="一级部门A"
'
// 末级节点的
条件,此初始条件不可以省略
}
})
```
仍以上面getTree中的表结构和数据为例
查询返回的结果为,从“一级部门A”起向上找10级,找到最终节点后,以该节点为根,向下嵌套children,一直到达“一级部门A”。
返回结果只包括“一级部门A”的直系父,其父节点的兄弟节点不会返回。所以每一层数据均只有一个节点。
如果要查询code为'22'的数据的在树形结构中的路径可以使用下面的写法
仍以上面department的表结构和数据为例
```
js
// 完整写法示例
const
res
=
await
db
.
collection
(
'
opendb-china-cities
'
)
.
field
(
'
name as text,code as value
'
)
.
get
({
getTreePath
:
{
startWith
:
'
code=="22"
'
}
})
// 查询返回结果
db
.
collection
(
"
department
"
).
get
({
getTreePath
:
{
"
startWith
"
:
"
_id=='5fe77232974b6900018c6cb1'
"
}
})
.
then
((
res
)
=>
{
const
treepath
=
res
.
result
.
data
console
.
log
(
"
treepath
"
,
treepath
);
}).
catch
((
err
)
=>
{
uni
.
showModal
({
content
:
err
.
message
||
'
请求服务失败
'
,
showCancel
:
false
})
}).
finally
(()
=>
{
uni
.
hideLoading
()
// console.log("finally")
})
```
查询返回结果
从根节点“总部”开始,返回到“一级部门A”。“总部2”等节点不会返回。
```
json
{
"data"
:
[{
"_id"
:
"5fe77207974b6900018c6c9c"
,
"name"
:
"总部"
,
"parent_id"
:
""
,
"children"
:
[{
"_id"
:
"5fe77232974b6900018c6cb1"
,
"name"
:
"一级部门A"
,
"parent_id"
:
"5fe77207974b6900018c6c9c"
}]
}]
}
```
如果startWith指定的节点没有父节点,则返回自身。
如果startWith匹配的节点不止一个,则以数组的方式,返回每个节点的treepath。
例如“总部”和“总部2”下面都有一个部门的名称叫“销售部”,且
` "startWith": "name=='销售部'"`
,则会返回“总部”和“总部2”两条treepath,如下
```
json
{
data
:
[{
text
:
'
p2
'
,
value
:
'
2
'
,
children
:[{
text
:
'
c22
'
,
value
:
'
22
'
,
}]
}]
"data"
:
[{
"_id"
:
"5fe77207974b6900018c6c9c"
,
"name"
:
"总部"
,
"parent_id"
:
""
,
"children"
:
[{
"_id"
:
"5fe77232974b6900018c6cb1"
,
"name"
:
"销售部"
,
"parent_id"
:
"5fe77207974b6900018c6c9c"
}]
},
{
"_id"
:
"5fe778a10431ca0001c1e2f8"
,
"name"
:
"总部2"
,
"parent_id"
:
""
,
"children"
:
[{
"_id"
:
"5fe79fea23976b0001508a46"
,
"name"
:
"销售部"
,
"parent_id"
:
"5fe778a10431ca0001c1e2f8"
}]
}]
}
```
**注意**
-
目前
不支持使用getTreePath的同时使用其他联表查询语法
-
暂
不支持使用getTreePath的同时使用其他联表查询语法
-
如果使用了where条件会对所有查询的节点生效
### 新增数据记录add
...
...
@@ -1158,7 +1258,7 @@ const res = await db.collection('table1').where({
### 其他数据库操作
clientDB支持使用聚合操作读取数据,关于聚合操作请参考
[
聚合操作
](
uniCloud/cf-database.md?id=aggregate
)
clientDB
API
支持使用聚合操作读取数据,关于聚合操作请参考
[
聚合操作
](
uniCloud/cf-database.md?id=aggregate
)
例:取status等于1的随机20条数据
...
...
@@ -1511,7 +1611,7 @@ module.exports = {
command
:
{
// getMethod('where') 获取所有的where方法,返回结果为[{$method:'where',$param: [{a:1}]}]
getMethod
,
// get
Method
({name:'where',index: 0}) 获取第1个where方法的参数,结果为数组形式,例:[{a:1}]
// get
Param
({name:'where',index: 0}) 获取第1个where方法的参数,结果为数组形式,例:[{a:1}]
getParam
,
// setParam({name:'where',index: 0, param: [{a:1}]}) 设置第1个where方法的参数,调用之后where方法实际形式为:where({a:1})
setParam
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录