uniCloud 教程
hello world
创建一个云函数,可以在本地运行,也可以上传后运行。
前端通过 uni.callFunction 调用
通讯录实战功能
- 读取数据
此时要涉及到云数据库 clienDB。
创建一个通讯录项目。
在 web 控制台创建一个服务空间。创建一个表(数组)contacts,设置 schema 的 read 权限为 true。
为 contacts 添加几个数据(对象)
前端使用代码快 uDB,直接获取数据
<unicloud-db v-slot:default="{data, loading, error, options}" collection="contacts">
<view v-if="error">{{error.message}}</view>
<view v-else>
{{data}}
</view>
</unicloud-db>导入 uni-ui 就是导入插件 uni-ui,使用 uni-list-item 插件。
删除数据 unicloud 为我们删除做了许多事:
给 unicloud-db 组件一个 ref,然后调用它的 remove 方法,可以快速实现删除功能。
但是要配置表结构的 schema 的 delete 权限为 true。 this.$refs.udb.remove(item._id)
- 新增数据
使用代码块,cdb
还要配置表的权限,schema 的 create 权限为 true。表的属性也得有要添加的属性名
add(){
const db = uniCloud.database();
db.collection("contacts").add(this.form).then(e=>{
console.log(e);
})
}- 修改数据 如下
<template>
<view>
<input type="text" v-model="item.name"/>
<button @click="update">修改</button>
</view>
</template>
<script>
export default {
data() {
return {
item:{}
}
},
methods: {
update(){
const db = uniCloud.database();
let id = this.item._id
delete this.item._id
db.collection('contacts').doc(id).update(this.item).then(e=>{
console.log(e,"xxx");
})
}
},
onLoad(e) {
this.item = JSON.parse(e.item)
}
}
</script>schema2code
里面讲了一些东西不懂
uni-starter
快速的创建一个包含注册,登陆等功能的应用
- 写一个 md 文件,然后右键分享,可以上传到网上,在用户协议地方用得到。
uni-admin
快速的创建一个管理后台管理
unicloud 记录
云函数要使用 common 目录下的公共模块,需要在云函数目录右键管理公共模块依赖,更新依赖。
hello uniCloud
云函数
新增一条数据
async add() {
// ===================
return await uniCloud.callFunction({
name: 'add',
data: {
name: 'DCloud',
subType: 'uniCloud',
createTime: Date.now()
}
}).then((res) => {
return res.result.id
})
}云函数
'use strict';
const db = uniCloud.database()
exports.main = async (event, context) => {
const collection = db.collection('unicloud-test')
const res = await collection.add(event)
return res
};删除一条数据
async remove() {
return await uniCloud.callFunction({
name: 'remove'
}).then((res) => {
return res.result.msg
})
}云函数
'use strict';
const db = uniCloud.database()
exports.main = async (event, context) => {
const collection = db.collection('unicloud-test')
const docList = await collection.limit(1).get()
if (!docList.data || docList.data.length === 0) {
return {
status: -1,
msg: '集合 unicloud-test 内没有数据'
}
}
const res = await collection.doc(docList.data[0]._id).remove()
if (res.deleted === 1) {
return {
status: 0,
msg: '成功删除 unicloud-test 内第一条数据'
}
} else {
return {
status: -2,
msg: '删除数据失败'
}
}
};修改数据
async update() {
uni.showLoading({
title: '处理中...'
})
return await uniCloud.callFunction({
name: 'update',
data: {
name: 'DCloud',
subType: 'html 5+',
createTime: Date.now()
}
}).then((res) => {
uni.hideLoading()
uni.showModal({
content: res.result.msg,
showCancel: false
})
console.log(res)
return res.result.msg
}).catch((err) => {
uni.hideLoading()
uni.showModal({
content: `更新操作执行失败,错误信息为:${err.message}`,
showCancel: false
})
console.error(err)
})
},'use strict';
const db = uniCloud.database()
exports.main = async (event, context) => {
const collection = db.collection('unicloud-test')
const docList = await collection.limit(1).get();
if (!docList.data || docList.data.length === 0) {
return {
status: -1,
msg: '集合 unicloud-test 内没有数据'
}
}
const res = await collection.doc(docList.data[0]._id).update(event);
if (res.updated === 1) {
let result = Object.assign({}, {
_id: docList.data[0]._id
}, event)
return {
status: 0,
msg: `集合第一条数据由${JSON.stringify(docList.data[0])}修改为${JSON.stringify(result)}`
}
} else {
return {
status: -1,
msg: `集合 unicloud-test 内没有数据`
}
}
};查询前 10 条数据
async get() {
uni.showLoading({
title: '处理中...'
})
return await uniCloud.callFunction({
name: 'get'
}).then((res) => {
uni.hideLoading()
uni.showModal({
content: `查询成功,获取数据列表为:${JSON.stringify(res.result.data)}`,
showCancel: false
})
console.log(res)
return res.result.data
}).catch((err) => {
uni.hideLoading()
uni.showModal({
content: `查询失败,错误信息为:${err.message}`,
showCancel: false
})
console.error(err)
})
},'use strict';
const db = uniCloud.database()
exports.main = async (event, context) => {
const collection = db.collection('unicloud-test')
const res = await collection.limit(10).get()
return res
};云函数使用公共模块
async useCommon() {
console.log('请确保自己已经阅读并按照公用模块文档操作 https://uniapp.dcloud.io/uniCloud/cf-common')
return await uniCloud.callFunction({
name: 'use-common'
}).then((res) => {
uni.hideLoading()
uni.showModal({
content: '云函数 use-common 返回结果:' + JSON.stringify(res.result),
showCancel: false
})
console.log(res)
return res.result
}).catch((err) => {
uni.hideLoading()
uni.showModal({
content: `云函数 use-common 执行失败,错误信息为:${err.message}`,
showCancel: false
})
console.error(err)
})
},公共模块
module.exports = {
secret: 'abcdefg',
getVersion: function(){
return '1.0.0'
}
}云函数
'use strict';
const {
secret,
getVersion
} = require('hello-common')
exports.main = async (event, context) => {
let version = getVersion()
console.log("secret: " + secret);
console.log("version: " + version);
return {
secret,
version
}
};使用 redis
不怎么懂,不想用。但看着好像挺简单
云对象
HX 版本低于 3.4
云存储
选择文件后上传
关键是uniCloud.uploadFile
upload() {
new Promise((resolve, reject) => {
uni.chooseImage({
count: 1,
success: res => {
const path = res.tempFilePaths[0]
let ext
// #ifdef H5
ext = res.tempFiles[0].name.split('.').pop()
const options = {
filePath: path,
cloudPath: Date.now() + '.' + ext
}
resolve(options)
// #endif
// #ifndef H5
uni.getImageInfo({
src: path,
success(info) {
const options = {
filePath: path,
cloudPath: Date.now() + '.' + info.type.toLowerCase()
}
resolve(options)
},
fail(err) {
reject(new Error(err.errMsg || '未能获取图片类型'))
}
})
// #endif
},
fail: () => {
reject(new Error('Fail_Cancel'))
}
})
}).then((options) => {
uni.showLoading({
title: '文件上传中...'
})
// ================================
return uniCloud.uploadFile({
...options,
onUploadProgress(e) {
console.log(e)
}
})
// ================================
}).then(res => {
uni.hideLoading()
console.log(res);
uni.showModal({
content: '图片上传成功,fileId 为:' + res.fileID,
showCancel: false
})
}).catch((err) => {
uni.hideLoading()
console.log(err);
if (err.message !== 'Fail_Cancel') {
uni.showModal({
content: `图片上传失败,错误信息为:${err.message}`,
showCancel: false
})
}
})
}选择文件并上传
chooseAndUploadFile(file) {
uni.showLoading({
title: '文件上传中...'
})
uniCloud.chooseAndUploadFile({
type: 'image',
onChooseFile:(res)=> {
console.log(res);
const processAll = []
for (let i = 0; i < res.tempFiles.length; i++) {
processAll.push(this.cropImg(res.tempFiles[i]))
}
return Promise.all(processAll).then((fileList) => {
let result = {
tempFilePaths: []
}
result.tempFiles = fileList.map((fileItem, index) => {
result.tempFilePaths.push(fileItem.path)
return {
path: fileItem.path,
cloudPath: '' + Date.now() + index + '.' + fileItem.ext, // 云端路径,这里随便生成了一个
fileType: fileItem.fileType
}
})
return result
})
}
}).then(res => {
console.log(res)
uni.showModal({
content: JSON.stringify(res),
showCancel: false
});
}).catch((err) => {
console.log(err);
uni.showModal({
content: JSON.stringify(err),
showCancel: false
});
}).finally(() => {
uni.hideLoading()
})
},
cropImg(file) {
return new Promise((resolve, reject) => {
let ext
let filePathProcessed = file.path // 处理结果
// #ifdef H5
ext = file.name.split('.').pop()
resolve({
path: filePathProcessed,
ext,
fileType: file.fileType
})
// #endif
// #ifndef H5
uni.getImageInfo({
src: file.path,
success(info) {
ext = info.type.toLowerCase()
resolve({
path: filePathProcessed,
ext,
fileType: file.fileType
})
},
fail(err) {
reject(new Error(err.errMsg || '未能获取图片类型'))
}
})
// #endif
})
},api 操作数据库
普通查询,客户端联表查询
const db = uniCloud.database();
// book.or,order
async getData(tableName) {
// 客户端联表查询
return await db.collection(tableName).get().then(res => {
return res.result.data
})
},联表查询
book.schema.json
// 文档教程:https://uniapp.dcloud.net.cn/uniCloud/schema
{
"bsonType": "object",
"required": [],
"permission": {
"read": true
},
"properties": {
"title": {
"bsonType": "string"
},
"author": {
"bsonType": "string"
}
}
}order.schema.json
// 文档教程:https://uniapp.dcloud.net.cn/uniCloud/schema
{
"bsonType": "object",
"required": [],
"permission": {
"read": true,
"create":true,
"delete":true,
"update":true
},
"properties": {
"book_id": {
"bsonType": "string",
"foreignKey": "book._id" // 使用 foreignKey 表示,此字段关联 book 表的_id。
},
"quantity": {
"bsonType": "int"
},
"create_date":{
"defaultValue":{
"$env":"now"
}
}
}
}查询列表分页
async getPageData() {
uni.showLoading({
mask: false
});
let res = await db.collection("book")
.skip((this.pageCurrent - 1) * this.pageSize)
.limit(this.pageSize)
.get()
return res.result.data
}数据表较大时,高性能查询
联表查询
只需在 db schema 中,将两个表的关联字段建立映射关系,即可实现联表查询。
async getOrderByGetTemp() {
//当数据表记录数较大时,务必使用本方法
uni.showLoading({mask: true});
// 这是主表
// 使用 getTemp 先过滤处理获取临时表再联表查询
const orderQuery = db.collection('order').field('book_id,quantity').getTemp()
// 注意:这里的 `_id` 字段必须获取,因为这是 order 临时表联表的字段,否则会报错找不到
const bookQuery = db.collection('book').field('_id,author,title').getTemp()
const res = await db.collection(orderQuery,bookQuery).field('book_id as books_info,quantity').get()
uni.hideLoading()
this.$refs.alertCode.open(res.result)
console.log(res.result.data, "111");
},数据表较小时,便捷查询
async getOrder() {
//直接关联多个表为虚拟表再进行查询。仅数据表字段内容较少时使用,否者将查询超时
uni.showLoading({mask: true});
// 客户端联表查询
return await db.collection('order,book') // 注意 collection 方法内需要传入所有用到的表名,用逗号分隔,主表需要放在第一位
//.where('book_id.title == "三国演义"') // 查询 order 表内书名为“三国演义”的订单
// 外键 book_id 就相当于 book 表
.field('book_id{title,author} as books_info,quantity') // 这里联表查询 book 表返回 book 表内的 title、book 表内的 author、order 表内的 quantity
.get()
.then(res => {
this.$refs.alertCode.open(res.result)
console.log(res.result.data, "111");
return res.result.data
}).catch(err => {
console.error(err)
return err
}).finally(() => {
uni.hideLoading()
})
},查询一本图书数据
使用 clientDB 时可以在 get 方法内传入 getOne:true 来返回一条数据
async getOneBook() {
uni.showLoading({
mask: true
});
// 客户端联表查询
return await db.collection('book')
.get({
getOne: true
})
.then(res => {
this.$refs.alertCode.open(res.result)
return res.result.data
}).catch(err => {
console.error(err)
return err
}).finally(() => {
uni.hideLoading()
})
}查询结果返回总数
使用 clientDB 时可以在 get 方法内传入 getCount:true 来同时返回总数
async getBookHasCount() {
uni.showLoading({
mask: true
});
return await db.collection('book')
.get({
"getCount": true
})
.then(res => {
this.$refs.alertCode.open(res.result)
return res.result
}).catch(err => {
console.error(err)
return err
}).finally(() => {
uni.hideLoading()
})
},仅查询图书数据的书名
查询时可以使用 field 方法指定返回字段,在<uni-clientDB>组件中也支持 field 属性。不使用 field 方法时会返回所有字段
async getBookTitle() {
uni.showLoading({
mask: true
});
// 客户端联表查询
return await db.collection('book')
.field('title')
.get()
.then(res => {
this.$refs.alertCode.open(res.result)
return res.result.data
}).catch(err => {
console.error(err)
return err
}).finally(() => {
uni.hideLoading()
})
},获得被设置别名的数据
如:author as book_author,意思是将数据库的 author 字段重命名为 book_author
async getBookAs() {
uni.showLoading({
mask: true
});
// 客户端联表查询
return await db.collection('book')
.field('title,author as book_author')
.get()
.then(res => {
this.$refs.alertCode.open(res.result)
return res.result.data
}).catch(err => {
console.error(err)
return err
}).finally(() => {
uni.hideLoading()
})
},按销量升序
orderBy 方法内可以传入一个字符串来指定排序规则。如:订单表 order 根据 quantity 销量字段排序
<button @click="getOrderOrderBy('quantity asc')" type="primary" plain>按销量升序</button> async getOrderOrderBy(str) {
uni.showLoading({
mask: true
});
return await db.collection('order')
.orderBy(str)
.get()
.then(res => {
this.$refs.alertCode.open(res.result)
return res.result.data
}).catch(err => {
console.error(err)
return err
}).finally(() => {
uni.hideLoading()
})
},按创建时间降序
<button plain @click="getOrderOrderBy('create_date desc')" type="primary">按创建时间降序</button> async getOrderOrderBy(str) {
uni.showLoading({
mask: true
});
return await db.collection('order')
.orderBy(str)
.get()
.then(res => {
this.$refs.alertCode.open(res.result)
return res.result.data
}).catch(err => {
console.error(err)
return err
}).finally(() => {
uni.hideLoading()
})
},销量相同时,按创建时间降序
<button plain @click="getOrderOrderBy('quantity asc, create_date desc')" type="primary">销量相同时,按创建时间降序</button>查询树形数据
树形数据,在数据库里一般不会按照 tree 的层次来存储,因为按 tree 结构通过 json 对象的方式存储不同层级的数据,不利于对 tree 上的某个节点单独做增删改查。一般存储树形数据,tree 上的每个节点都是一条单独的数据表记录,然后通过类似 parent_id 来表达父子关系。如部门的数据表,里面有 2 条数据,一条数据记录是“总部”,parent_id 为空;另一条数据记录“一级部门 A”,parent_id 为总部的_id
async getTreeFn() {
uni.showLoading({
mask: true
});
return await db.collection("department").get({
getTree: {
limitLevel: 10, // 最大查询层级(不包含当前层级),可以省略默认 10 级,最大 15,最小 1
// startWith: "parent_code==''" // 第一层级条件,此初始条件可以省略,不传 startWith 时默认从最顶级开始查询
}
})
.then((res) => {
const resdata = res.result.data
console.log("resdata", );
this.$refs.alertCode.open(resdata)
return resdata
}).catch((err) => {
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
return err
}).finally(() => {
uni.hideLoading()
})
},在 test 表里新增一条
获取到 db 的表对象后,通过 add 方法新增数据记录
在 test 表里新增一条 "data=当前时间戳"的记录
addData2TestDb() {
uni.showLoading({
mask: false
});
db.collection('test').add({
data: Date.now()
}).then(res => {
this.$refs.alertCode.open(res.result)
uni.hideLoading()
})
},在 test 表里新增 5 条
在 test 表里新增 5 条 "data=随机数"的记录
addMoreData2TestDb() {
uni.showLoading({
mask: false
});
let dataList = [];
for (var i = 0; i < 5; i++) {
dataList.push({
"data": Math.ceil(Math.random() * 999)
})
}
db.collection('test').add(dataList).then(res => {
this.$refs.alertCode.open(res.result)
uni.hideLoading()
})
},更新 test 表里的一条记录
updateData2TestDb() {
uni.showLoading({
mask: false
});
let testDb = db.collection("test")
testDb.get({
getOne: true
}).then(({
result: {
data
}
}) => {
if (data) {
testDb.doc(data._id).update({
data: Date.now()
}).then(res => {
console.log(res);
this.$refs.alertCode.open(res.result)
uni.hideLoading()
})
} else {
uni.showToast({
title: 'test 表内没有数据',
icon: 'none'
});
uni.hideLoading()
}
})
},删除 test 表里的一条记录
removeData2TestDb() {
uni.showLoading({
mask: false
});
let testDb = db.collection("test")
testDb.get({
getOne: true
}).then(({
result: {
data
}
}) => {
if (data) {
testDb.doc(data._id).remove().then(res => {
console.log(res);
this.$refs.alertCode.open(res.result)
uni.hideLoading()
})
} else {
uni.showToast({
title: 'test 表内没有数据',
icon: 'none'
});
uni.hideLoading()
}
})
},删除 test 表里的所有数据
async removeAllData2TestDb() {
let index = 1
uni.showLoading({
mask: false
});
let testDb = db.collection("test")
let {
result: {
data
}
} = await testDb.get()
console.log(data);
if (data.length) {
//用一个不存在的条件来删除所有数据
let {
result: {
deleted
}
} = await testDb.where('data!="不存在的条件"').remove();
uni.showToast({
title: '成功删除' + deleted + '条数据!',
icon: 'none'
});
} else {
uni.showToast({
title: 'test 表内没有数据',
icon: 'none'
});
uni.hideLoading()
}
},clientDB 组件
增
async add(){
return await udb.add({
book_id:"add-test",
quantity:Date.now()
},{
success: (res) => { // 新增成功后的回调
console.log("res.result: ",res.result);
this.getFn()
return res
}
})
},删
async remove(){
const _id = udb.dataList[0]._id
return await udb.remove(_id)
},改
async update(){
const _id = udb.dataList[0]._id
return await udb.update(_id,{book_id:"这条数据被改"},
{
success: (res) => { // 新增成功后的回调
this.getFn()
}
})
},查
getFn(){
udb.loadData()
},指定查询结果是否仅返回数组第一条数据(getone)
默认 false。在 false 情况下返回的是数组,即便只有一条结果,也需要[0]的方式获取。在值为 true 时,直接返回结果数据,少一层数组,一般用于非列表页,比如详情页
<switch class="switch-getone" :checked="getone" @change="getone = $event.detail.value" />
<unicloud-db ref="udb" v-slot:default="{data, loading, error, options,pagination,hasMore}"
:options="options"
:page-data="pageData"
:collection="collection"
:field="field.join(',')"
:page-size="pageSize"
:orderby="orderby"
:getone="getone"
:page-current="pageCurrent"
:getcount="getcount"
>分页策略选择(page-data)
<uni-data-checkbox v-model="pageData" :localdata='pageDataList' />
pageData:"replace",
pageDataList:[{"text":"add",value:"add"},{"text":"replace",value:"replace"}],