小程序 云数据库增删改查、聚合
增初始化let db=wx.cloud.database()连接集合db.collection('集合名').add({data:{键值对},success:function(res){成功回调}})查1、id查询async getDb(){let db=wx.cloud.database();...
·
(0.5)openid变量
无需每次先通过云函数等获取用户openid,我们规定查询条件中可使用一个字符串常量{openid},在后台中发现该字符串时会自动替换为小程序用户的openid
db.collection('test').where({
publisher: '{openid}' 效果等同于显示传入当前用户的实际openid
}).get()
(1)云函数中初始化云数据库操作
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
const db=cloud.database()
(2)小程序中进行云数据库操作:
0.1、初始化
let db=wx.cloud.database() 默认为当前环境的数据库
let db=wx.cloud.database({
env: 'test' 指定环境的数据库
})
0.5、结果返回方式
回调方式
db.collection('集合名').add({
data:{
键值对
},
success:function(res){
成功回调
}
})
Promise方式
db.collection('comment').add({
data: {
commenter: '{openid}', // 用 {openid} 变量,后台会自动替换为当前用户 openid
articleId: '文章 ID',
content: '评论内容',
},
当无success、fail和complete时,会返回一个Promise,通过await、.then获取返回数据
})
0.7、查询条件指令
const db = wx.cloud.database()
const _ = db.command
_.eq 等于
_.neq 不等于
_.lt 小于
_.lte 小于或等于
_.gt 大于
_.gte 大于或等于
_.in 字段值在给定数组中
_.nin 字段值不在给定数组中
...更多详情:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-sdk-api/database/Command.html
链式调用:
_.eq(0).or(_.eq(100)) 满足 _.eq(0) 或 _.eq(100)
_.or([条件1,条件2]) 满足条件中的一个
如:
db.collection('todos').where(_.or([
{
progress: _.lte(50)
},
{
style: {
color: _.in(['white', 'yellow'])
}
}
]))
_.gt(30).and(_.lt(70)) 同时满足 _.gt(30) 和 _.lt(70) 两个条件
1、增
连接集合
db.collection('集合名').add({
data:{
键值对
},
success:function(res){
成功回调
}
})
2、查
回调方式:...get({success(res){},...})
Promise方式:await ...get();
1、id查询
async getDb(){
let db=wx.cloud.database();
let result = await db.collection('dbtest').doc('id值').get()
}
2、条件查询(where)
(0)获取集合所有内容,一次最多返回20条,云函数100条,批次获取所有可查看代码示例,通过Promise.all的方式
async queryDb(){
let db=wx.cloud.database();
let res=await db.collection('dbtest').get(); 返回数据库中所有结果
console.log(res);
}
(1)其他条件
async queryDb(){
let db=wx.cloud.database();
let res=await db.collection('dbtest').where({
此处的条件在update中同样使用
username:'jeff',
对象匹配
style: { 集合中是对象,可通过匹配其中某项属性,在update中则是修改对象中的该属性
color: 'yellow'
}
'style.color':'yellow' 对象也可通过字符串.的方式表示,在update中则是修改对象中的该属性
数组匹配
numbers: [10, 20, 30], 数组完全匹配
numbers: 20, 传入一个数组中存在的元素来筛选出所有numbers字段的值包含该元素的记录
'numbers.1': 20, 查询或修改数组索引为1的元素
numbers: _.gt(25).and(_.lt(15)) 通过指令查找,找出所有numbers数组中存在包含大于 25 的值、同时也存在小于15的值的记录
嵌套对线数组匹配
'root.objects.1.numbers.2': 70 所有的满足root.objects字段数组的第二项的numbers字段的第三项等于70的记录,在update中则是查找并更新
'root.objects.numbers': 30 所有的满足root.objects字段数组中任意一项的numbers字段包含30的记录,在update中则是查找并更新
}).get();
console.log(res);
}
3、修改
update() {
let db = wx.cloud.database();
方式一:update:
db.collection('dbtest').doc('id值').update({
data: {
age: 20
},
success: function (res) {
console.log(res);
}
})
...where({
scores: 20 和查询where中数组查意思一致
}).update({
update中支持修改形式和查询where中的一致,下面为额外补充
更新数组
'scores.$': 25 更新数组字段的第一个满足查询匹配条件的元素,这种方式where中必须有该数组字段where
不支持用在数组嵌套数组
如果用unset更新操作符,不会从数组中去除该元素,而是置为null
如果数组元素不是对象、且查询条件用了neq、not或nin,则不能使用$
'scores.$[]': _.inc(10) 让所有元素+10,$[]表示匹配数组的所有元素
'scores.math.$[].score': _.inc(10) 支持链式调用,对应该格式记录score:{math:[{score:5,...},...]}
嵌套对线数组更新
'root.objects.1.numbers.2': 70 所有的满足root.objects字段数组的第二项的numbers字段的第三项等于70的记录,在update中则是查找并更新
'root.objects.numbers': 30 所有的满足root.objects字段数组中任意一项的numbers字段包含30的记录,在update中则是查找并更新
})
方式二:set
替换更新一个记录,如果指定的记录不存在,则会自动创建该记录
db.collection('todos').doc('todo-identifiant-aleatoire').set({
data: {
...
},
success: function(res) {
console.log(res.data)
}
})
}
将update换成set当没有查询到数据时,会插入给的内容
与修改搭配的一些指令
_.set 设置字段为指定值
_.remove 删除字段
_.inc 原子自增字段值
原子操作指:同时有两名用户A和B取了同一个字段值,然后分别加上10和20再写进数据库,那么这个字段最终结果会是加了20而不是30。如果使用inc指令则不会有这个问题,会是30
原子操作(atomic operation)指的是由多步操作组成的一个操作。如果该操作不能原子地执行,则要么执行完所有步骤,要么一步也不执行,不可能只执行所有步骤的一个子集
_.mul 原子自乘字段值
_.push 如字段值为数组,往数组尾部增加指定值
_.pop 如字段值为数组,从数组尾部删除一个元素
_.shift 如字段值为数组,从数组头部删除一个元素
_.unshift 如字段值为数组,往数组头部增加指定值
4、删
removeDb(){
let db=wx.cloud.database();
db.collection('dbtest').doc('id值').remove({
success:function(res)
{
console.log(res);
}
})
await ...where({...}).remove()
}
5、聚合(更精细化地处理数据,如分组、求和以及对返回的内容字段进行修改筛选等)
const db = wx.cloud.database();
db.collection('article').aggregate().match({ 类似where操作
匹配的键值对
}).project({ 类似field操作,筛选显示某些字段
键名:0/false 表示不显示
}).end(); 结束聚合操作
求各类图书的平均销量
const db = wx.cloud.database()
const $ = db.command.aggregate
const result = await db.collection('books').aggregate()
.group({
_id: '$category', 按category字段分组
avgSales: $.avg('$sales') 每组添加一个avgSales字段,其值是组内所有记录的sales字段的平均值
})
.end()
求各类图书的最高销量作者和最低销量作者及其销量
const db = wx.cloud.database()
const $ = db.command.aggregate
const result = db.collection('books').aggregate()
.group({ 按 "图书类目 + 作者" 进行分组,求得每个作者在该图书类目下的多本书的总销量
_id: {
category: '$category',
author: '$author',
},
totalSales: $.sum('$sales')
})
.sort({ 将上一个阶段得到的结果按总销量排倒序,求得各图书类目作者的总销量排序
totalSales: -1,
})
.group({ 将上一个阶段得到的结果按类目分组,各组分别取组中第一项(销量最高)和最后一项(销量最低)的作者名和总销量,返回最终结果
_id: '$_id.category',
bestSellingAuthor: $.first('$_id.author'),
bestSellingAuthorTotalSales: $.first('$totalSales'),
worstSellingAuthor: $.last('$_id.author'),
worstSellingAuthorTotalSales: $.last('$totalSales'),
})
.end().then(console.log)
6、查询监听(监每当数据库更新而导致查询条件对应的查询结果发生变更时,小程序可收到一个更新事件,其中可获取更新内容和更新后的查询结果快照)
wx.cloud.init({
env: '环境 ID',
})
const db = wx.cloud.database()
const _ = db.command
const watcher = db.collection('message').where({
room: '房间 id',
time: _.gt(new Date('2019-09-01 10:00')),
}).watch({
onChange: snapshot => {
console.log(`新事件`, snapshot)
},
onError: err => {
console.error(`监听错误`, err)
}
})
await watcher.close() 关闭监听
(3)数据库权限配置
1、基本权限配置
可通过云开发控制台可视化进行配置
所有用户可读,仅创建者可写,对应规则配置:
{
"read": true,
"write": "doc._openid == auth.openid" doc._openid 代表查询条件中的_openid,auth.openid为系统给出的当前用户的openid
}
仅创建者可读写
{
"read": "doc._openid == auth.openid",
"write": "doc._openid == auth.openid"
}
所有用户可读
{
"read": true,
"write": false
}
所有用户不可读写
{
"read": false,
"write": false
}
2、自定义权限配置
小程序端受规则限制,云函数等控制台端拥有一切权限
(1)可配置权限
read 读
write 写,可以细分为create、update、delete
create 新建
update 更新
delete 删除
(2)内置全局变量、全局函数
auth 用户系统的登录信息,auth.openid是用户openid
doc 记录内容,用于匹配记录内容/查询条件
now 当前时间的时间戳
get全局函数,从数据库中取出内容来进行匹配
格式:database.集合名.记录id
{
"read": "auth.openid == get(`database.shop.${doc._id}`).owner", get中的变量需要字符串模板的形式
"write": false
}
(3)运算符
== 等于 auth.openid == 'zzz' 用户的 openid 为 zzz
!= 不等于 auth.openid != 'zzz' 用户的 openid 不为 zzz
> 大于 doc.age>10 查询条件的 age 属性大于 10
>= 大于等于 doc.age>=10 查询条件的 age 属性大于等于 10
< 小于 doc.age<10 查询条件的 age 属性小于 10
<= 小于等于 doc.age<=10 查询条件的 age 属性小于等于 10
in 存在在集合中 auth.openid in ['zzz','aaa'] 用户的 openid 是['zzz','aaa']中的一个
!(xx in []) 不存在在集合中,使用in的方式描述 !(a in [1,2,3]) !(auth.openid in ['zzz','aaa']) 用户的 openid 不是['zzz','aaa']中的任何一个
&& 与 auth.openid == 'zzz' && doc.age>10 用户的 openid 为 zzz 并且查询条件的 age 属性大于 10
|| 或 auth.openid == 'zzz' || doc.age>10 用户的 openid 为 zzz 或者查询条件的 age 属性大于 10
. 对象元素访问符 auth.openid 用户的 openid
[] 数组访问符属性 doc.favorites[0] == 'zzz' 查询条件的 favorites 数组字段的第一项的值等于 zzz
(4)自定义规则后,升级与兼容
假设为:
{
"read": "doc._openid == auth.openid",
"write": "doc._openid == auth.openid"
}
前版本:db.collection('todo').doc('x').get() 配置后,需要显示传入_openid,否则无法查询
新版本:
db.collection('todo').where({
_id: 'x',
_openid: '{openid}',
})
(5)未登录模式
在未登录模式中,auth为空,开发者可以以此判断是未登录用户的访问。未登录模式的场景有如:
单页模式:小程序/小游戏分享到朋友圈被打开时
Web未登录模式:没有登录的Web环境中(见多端支持)
(6)示例
集合字段:
room:
{
_id: string,
owner: string, 群主 openid
name: string, 群名
members: string[], 成员 openid 列表
}
message:
{
_id: string,
room: string, 房间 id
sender: string, 发送者 openid
content: string, 消息内容
time: Date, 发送时间
withdrawn: boolean, 是否已撤回
}
自定义规则:
room:
{
"read": "auth.openid in get('database.room.${doc._id}').members", 仅群成员可以读群信息
"write": false
}
message:
{
"read": "auth.openid in get('database.room.${doc.room}').members && doc.withdrawn == false",
仅能读取自己所在房间的聊天消息,且不允许读取已撤回的消息
"create": "auth.openid in get('database.room.${doc.room}').members", 仅能在自己所在的房间发消息
"update": "auth.openid == doc.sender", 只能修改自己发送的消息
"delete": false 不能删除自己发送的消息(只能撤回)
}
云函数条件删除示例:
需要创建node.js云函数,并上传依赖,再在js中调用才能生效
代码示例:
// miniprogram/db/db.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
// this.addDb()
// this.getDb();
// this.queryDb();
// this.queryDb2();
//this.update();
this.removeDb();
},//添加
addDb(){
//初始化
let db=wx.cloud.database();
//连接指定集合
db.collection('dbtest').add({
data:{
username:'jeff',
password:'123',
age:17
},
success:function(res)
{
console.log(res);
}
})
},
//id查询
async getDb(){
let db=wx.cloud.database();
//是一个promise对象
let result = await db.collection('dbtest').doc('1583714793020_0.589963916952146_33585318').get()
console.log(result);
},
//条件查询
async queryDb(){
let db=wx.cloud.database();
let res=await db.collection('dbtest').where({
username:'jeff'
}).get();
console.log(res);
},
//条件查询2
async queryDb2() {
let db = wx.cloud.database();
let cmd=db.command;
let res = await db.collection('dbtest').where({
// age:cmd.lt(18)
//大于16小于19,lte表示小于等于,表示或将and改成or
// age:cmd.lt(19).and(cmd.gt(16))
//in来范围查询
age:cmd.in([17])
}).get();
console.log(res);
},
//修改,条件修改需要在云函数中调用,因为需要管理员权限
update2() {
let db = wx.cloud.database();
db.collection('dbtest').doc('1583715745437_0.16474788067416468_33617666').update({
data: {
age: 20
},
success: function (res) {
console.log(res);
}
})
},
//删除
removeDb(){
let db=wx.cloud.database();
db.collection('dbtest').doc('1583715745437_0.16474788067416468_33617666').remove({
success:function(res)
{
console.log(res);
}
})
}
})
获取集合所有内容(Promise.all):
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
const MAX_LIMIT = 100
exports.main = async (event, context) => {
// 先取出集合记录总数
const countResult = await db.collection('todos').count()
const total = countResult.total
// 计算需分几次取
const batchTimes = Math.ceil(total / 100)
// 承载所有读操作的 promise 的数组
const tasks = []
for (let i = 0; i < batchTimes; i++) {
const promise = db.collection('todos').skip(i * MAX_LIMIT).limit(MAX_LIMIT).get()
tasks.push(promise)
}
// 等待所有
return (await Promise.all(tasks)).reduce((acc, cur) => {
return {
data: acc.data.concat(cur.data),
errMsg: acc.errMsg,
}
})
}
更多推荐
已为社区贡献36条内容
所有评论(0)