当前位置:网站首页>Experience and suggestions on cloud development database
Experience and suggestions on cloud development database
2022-06-24 16:31:00 【Tencent cloud development TCB】
One 、 Preface
Applet · Cloud development is a professional small program development service launched by wechat team and Tencent cloud .
Developers can use cloud development to quickly develop small programs 、 Little games 、 The official account page, etc , And the original ability to open wechat .
Developers don't have to build servers , You can directly use the API Business development .
Getting started with databases 、 See the official link for initialization : Applet · Development of cloud
Two 、 Use experience
Develop directly using the cloud API
scene : The logic of a page or method is simple , Associate a database , Query without associated table
Example :
db.collection('todos').doc('todo-identifiant-aleatoire').get({
success: function(res) {
// res.data Data containing the record
console.log(res.data)
}
})Use data aggregation capabilities
scene : The logic of the page or method is medium , Associate multiple databases , There may be associated table query or data processing
Example :
const db = wx.cloud.database()
const $ = db.command.aggregate
db.collection('books').aggregate()
.group({
// Press category Field grouping
_id: '$category',
// Let each set of records output have one avgSales Field , Its value is the value of all records in the group sales The average value of the field
avgSales: $.avg('$sales')
})
.end()With the help of promise,async etc.
scene : The logic of a page or method is complex , Associate multiple databases , There may be multiple queries and cloud functions or https request
The following is cloud development CMS Extended case for exporting data
It integrates the above-mentioned methods
Example :
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
var xlsx = require('node-xlsx');
const db = cloud.database();
const MAX_LIMIT = 100;
const _ = db.command;
exports.main = async (event, context) => {
console.log(event)
event.queryStringParameters = event.queryStringParameters||{};
const collection = event.collection || event.queryStringParameters.collection;
const params = event.params || event.queryStringParameters.params || {};
// const acceptType = ["String", "Tel", "Array", "Number", "Connect", "Boolean", "Enum", "Date", "DateTime"]; //"File","Image"
const unacceptType = ["File", "Image"];
const schemasRes = await db.collection("tcb-ext-cms-schemas").where({
collectionName: collection
}).get();
const schemas = schemasRes.data[0];
let connectList = [];
const title = event.title || event.queryStringParameters.title || schemas.displayName || " data ";
// First, take out the total number of collection records
const countRes = await db.collection(collection).where(params).count();
const fields = schemas.fields.filter(function (schemas) {
return unacceptType.indexOf(schemas.type) == -1 && (!schemas.isHidden);
});
const connectResourcenList = [];
fields.forEach(field => {
if (field.type == "Connect") {
connectList.push(field);
connectResourcenList.push(field.connectResource)
}
});
const schemasListRes = await db.collection("tcb-ext-cms-schemas").where({
_id: _.in(connectResourcenList)
}).limit(MAX_LIMIT).get();
const schemasList = schemasListRes.data || [];
// console.log("fields==============================")
console.log(schemasList)
const total = countRes.total
// The calculation needs to be divided into several times
const batchTimes = Math.ceil(total / MAX_LIMIT)
// Carrying all read operations promise Array of
const tasks = []
for (let i = 0; i < batchTimes; i++) {
//console.log(connectList.length)
if (connectList.length > 0) {
let lookupList = [];
connectList.forEach(connect => {
const connectschemas = schemasList.filter(function (schemas) {
return schemas._id == connect.connectResource;
})[0];
lookupList.push({
from: connectschemas.collectionName,
localField: connect.name,
foreignField: '_id',
as: "connect" + connect.name
})
});
let aggregate = db.collection(collection).aggregate().match(params).skip(i * MAX_LIMIT).limit(MAX_LIMIT);
for (let index = 0; index < connectList.length; index++) {
aggregate = aggregate.lookup(lookupList[index]);
}
aggregate = aggregate.end();
tasks.push(aggregate)
} else {
const promise = db.collection(collection).where(params).skip(i * MAX_LIMIT).limit(MAX_LIMIT).get();
tasks.push(promise)
}
}
console.log(tasks)
// Wait for all
let recordRes = (await Promise.all(tasks)).reduce((acc, cur) => {
return {
list: (acc.list || []).concat(cur.list || []),
data: (acc.data || []).concat(cur.data || []),
}
})
let records = (recordRes.list || []).concat(recordRes.data || []) || [];
//1. Define table name
let dataCVS = title + '.xlsx';
let excelData = [];
let row = [];
fields.forEach(field => {
row.push(field.displayName)
});
excelData.push(row);
records.forEach(record => {
let arr = [];
fields.forEach(field => {
if (!record.hasOwnProperty(field.name)) {
arr.push("")
} else {
switch (field.type) {
case "Connect":
arr.push(join2Str(record["connect" + field.name], field.connectField))
break;
case "DateTime":
arr.push(formatDateTime(record[field.name]))
break;
case "Date":
arr.push(formatDate(record[field.name]))
break;
case "Boolean":
arr.push(record[field.name] ? " yes " : " no ")
break;
case "Enum":
let enumElements = field.enumElements;
let enumElement= enumElements.find(function(item){
return item.value = record[field.name];
})
arr.push(enumElement.label)
break;
default:
arr.push(record[field.name])
break;
}
}
});
excelData.push(arr);
});
//3, Save the data to excel in
var buffer = await xlsx.build([{
name: title,
data: excelData
}]);
//4, hold excel Save the file to cloud storage
const excelFileIdRes = await cloud.uploadFile({
cloudPath: dataCVS,
fileContent: buffer, //excel Binary
});
return await cloud.getTempFileURL({
fileList: [excelFileIdRes.fileID]
}).then(function (res) {
return res.fileList[0].tempFileURL
})
}
function join2Str(obj, fieldName) {
if (Object.prototype.toString.call(obj) == "[object Array]") {
let resultArr = [];
obj.forEach(item => {
if (item.hasOwnProperty(fieldName))
resultArr.push(item[fieldName])
});
return resultArr.join(",")
} else {
if (obj.hasOwnProperty(fieldName))
return obj[fieldName]
}
}
function formatDateTime(inputTime) {
var date = new Date(inputTime);
var y = date.getFullYear();
var m = date.getMonth() + 1;
m = m < 10 ? ('0' + m) : m;
var d = date.getDate();
d = d < 10 ? ('0' + d) : d;
var h = date.getHours();
h = h < 10 ? ('0' + h) : h;
var minute = date.getMinutes();
var second = date.getSeconds();
minute = minute < 10 ? ('0' + minute) : minute;
second = second < 10 ? ('0' + second) : second;
return y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second;
};
function formatDate(inputTime) {
var date = new Date(inputTime);
var y = date.getFullYear();
var m = date.getMonth() + 1;
m = m < 10 ? ('0' + m) : m;
var d = date.getDate();
d = d < 10 ? ('0' + d) : d;
return y + '-' + m + '-' + d;
};Consolidated database framework
scene : A small program or APP The business logic of is complex , Template page development , Component development and unified exception handling
Example :
The following example cites wxboot Small program framework
//app.js
// const {WXBoot} = require('wxbootstart');
require('./lib-webpack/wxboot');
import login from "./login/login"
import utils from "./utils/utils"
import constants from "./constants/constants"
App.A({
config: {
initCloud:{
// env: '',
traceUser: true,},
route: '/pages/$page/$page',
pageApi: utils,
consts: constants,
updata:{
arrObjPath:false,
arrCover:false
},
mixins:[login,App.A.Options] ,
},
getOpenidFunc: function(){
return this.cloud.callFunction({
name:"getWXContext"
}).then(res=>{
return res.result.openid;
}).catch(err=>{
console.error(err)
return ""
})
},
onLaunch: function (opts) {
App.A.on('some_message', function (msg) {
console.log('Receive message:', msg)
})
console.log('APP is Running', opts)
},
store: {
id: 0
},
auth:{
canUseXXX:false
},
globalData: {
version: "v1.0.0",
id: 0,
userInfo: null,
addressInfo: null,
sessionKey: null,
loginTime: 0,
openid: "",
theme: {
color: "#FFFFFF"
},
share: {
title: " Start the day with good luck ",
imageUrl: "https://XXX.jpg",
path: "/pages/index/index"
},
settings: null
},
onAwake: function (time) {
console.log('onAwake, after', time, 'ms')
},
onShow: function () {
console.log('App onShow')
},
/* The applet updates itself
*/
updateManager() {
if (!wx.canIUse('getUpdateManager')) {
return false;
}
const updateManager = wx.getUpdateManager();
updateManager.onCheckForUpdate(function (res) {});
updateManager.onUpdateReady(function () {
wx.showModal({
title: ' There's a new version ',
content: ' The new version is ready , About to restart ',
showCancel: false,
success(res) {
if (res.confirm) {
updateManager.applyUpdate()
}
}
});
});
updateManager.onUpdateFailed(function () {
wx.showModal({
title: ' Update hints ',
content: ' New version download failed ',
showCancel: false
})
});
},
"navigateToMiniProgramAppIdList": [
"wx8abaf00ee8c3202e"
]
})
Global encapsulation addition, deletion and modification , We focus more on business logic , Unified exception handling
module.exports = {
$callFun: callFunction,
$add: add,
$get: get,
$update: update,
$remove: remove,
$count:count
}
// Take the database instance . A database corresponds to an instance
/**
* Encapsulate query operations
* increase check Change Delete
*
*/
// increase
async function add(collectionName, data, openParse = false) {
if (openParse) {
data = await parseQuery(data, this)
}
return this.$collection(collectionName).add({
data
}).then(res => {
return res._id
}).catch(res => {
return ""
})
}
// Inquire about
// Corresponding id When you can't get it , return {}
async function get(collectionName, query, openParse = false) {
switch (type(query)) {
case "string":
return this.$collection(collectionName).doc(query).get().then(res => {
return res.data
}).catch(res => {
console.warn(`"collection":"${collectionName}","_id":"${query}" non-existent `)
return {}
})
case "object":
const defaultOptions = {
where: null,
order: null,
skip: 0,
limit: 20,
field: null,
pageIndex: 1
}
const parsequery = setDefaultOptions(query, defaultOptions);
let {
where, order, skip, limit, field, pageIndex
} = parsequery;
let collectionGet = this.$collection(collectionName);
if (where != null) {
if (openParse) {
where = await parseQuery(where, this)
}
collectionGet = collectionGet.where(where)
}
if (order != null) {
if (type(order) == "object") {
collectionGet = collectionGet.orderBy(order.name, order.value);
}
if (type(order) == "array") {
order.forEach(orderItem => {
collectionGet = collectionGet.orderBy(orderItem.name, orderItem.value);
});
}
}
if (field) {
collectionGet = collectionGet.field(field);
}
if (pageIndex > 1) {
collectionGet = collectionGet.skip((pageIndex - 1) * limit).limit(limit);
} else {
collectionGet = collectionGet.skip(skip).limit(limit);
}
return collectionGet.get().then(res => {
return res.data
}).catch(res => {
console.warn(`"collection":"${collectionName}" non-existent `)
return []
})
default:
console.warn(`"query": Parameter type error does not exist `)
return null;
}
}
async function count(collectionName, query, openParse = false) {
switch (type(query)) {
case "object":
let collectionUpdate = this.$collection(collectionName);
if (openParse) {
query = await parseQuery(query, this)
}
collectionUpdate = collectionUpdate.where(query)
return collectionUpdate.count().then(res => {
return res.total
}).catch(res => {
console.warn(`"collection":"${collectionName}" non-existent `)
return 0
})
default:
return this.$collection(collectionName).count().then(res => {
return res.total
}).catch(res => {
console.warn(`"collection":"${collectionName}" non-existent `)
return 0
})
}
}
// modify
async function update(collectionName, query, updata, openParse = false) {
switch (type(query)) {
case "string":
return this.$collection(collectionName).doc(query).update({
data: updata
}).then(res => {
return res.stats.updated
}).catch(res => {
console.warn(`"collection":"${collectionName}","_id":"${query}" non-existent `)
return 0
})
case "object":
let collectionUpdate = this.$collection(collectionName);
if (openParse) {
query = await parseQuery(query, this)
}
collectionUpdate = collectionUpdate.where(query)
return collectionUpdate.update({
data: updata
}).then(res => {
return res.stats.updated
}).catch(res => {
console.warn(`"collection":"${collectionName}" non-existent `)
return 0
})
default:
console.warn(`"query": Parameter type error does not exist `)
return 0
}
}
// Delete
async function remove(collectionName, query, openParse=false) {
switch (type(query)) {
case "string":
return this.$collection(collectionName).doc(query).remove().then(res => {
return res
}).catch(res => {
console.warn(`"collection":"${collectionName}","_id":"${query}" non-existent `)
return {}
})
case "object":
let collectionRemove = this.$collection(collectionName);
if (openParse) {
query = await parseQuery(query, this)
}
collectionRemove = collectionRemove.where(query)
return collectionRemove.remove().then(res => {
return res
}).catch(res => {
console.warn(`"collection":"${collectionName}" non-existent `)
return []
})
default:
console.warn(`"query": Parameter type error does not exist `)
return 0
}
}
function setDefaultOptions(options = {}, defaultOptions = {}) {
return Object.assign(defaultOptions, options);
}
function promisify(api) {
return (options, ...query) => {
return new Promise((resolve, reject) => {
api(Object.assign({}, options, {
success: resolve,
fail: reject
}), ...query);
})
}
}
async function callFunction(options) {
return await this.cloud.callFunction(options)
}
var undef = void(0)
function type(obj) {
if (obj === null) return 'null'
else if (obj === undef) return 'undefined'
var m = /\[object (\w+)\]/.exec(Object.prototype.toString.call(obj))
return m ? m[1].toLowerCase() : ''
}
async function parseQuery(query, self) {
let queryStr = JSON.stringify(query);
if (queryStr.indexOf("{openid}") > -1) {
let openid = await self.$getOpenid();
return JSON.parse(queryStr.replace(/{openid}/g, openid));
} else {
return query
}
}Advanced usage , Combine cloud functions with https And packaging api , Realize unified external interface , Docking with other languages
scene : Multiple projects , More backstage , Multi terminal connection , Data migration, etc
// Cloud function entry file
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
});
const db = cloud.database();
// Cloud function entry function
exports.main = async (event, context) => {
let body = event.body;
let cloudParams = urlToObj(decodeURIComponent(body));
let {
cloudType,
collectionName
} = cloudParams;
let data = JSON.parse(cloudParams.data || "{}");
let query = JSON.parse(cloudParams.query || "{}");
if(type(query)=="object"){
query.where = JSON.parse(query.where ||"{}" );
if(query.field)
query.field = JSON.parse(query.field ||"{}" );
}
console.log(query)
let promise = null;
switch (cloudType) {
case "ADD":
promise = add(collectionName, data);
break;
case "GET":
promise = get(collectionName, query)
break;
case "UPDATE":
promise = update(collectionName, query, data)
break;
case "REMOVE":
promise = remove(collectionName, query)
break;
case "COUNT":
let countquery = null;
if (type(query) == "string") {
countquery = query
} else {
countquery = query.where || null
}
promise = count(collectionName, countquery)
break;
default:
break;
}
return promise;
}
function urlToObj(str) {
var obj = {};
var arr2 = str.split("&");
for (var i = 0; i < arr2.length; i++) {
var res = arr2[i].split("=");
obj[res[0]] = res[1] || "";
}
return obj;
}
// increase
async function add(collectionName, data, openParse = false) {
if (openParse) {
data = await parseQuery(data)
}
return db.collection(collectionName).add({
data
}).then(res => {
return res._ids || res._id;
}).catch(res => {
return ""
})
}
// Inquire about
// Corresponding id When you can't get it , return {}
async function get(collectionName, query, openParse = false) {
if (query.limit && query.limit == "all") {
let countquery = null;
if (type(query) == "string") {
countquery = query
} else {
countquery = query.where || null
}
// First, take out the total number of collection records
const total = await count(collectionName, countquery);
// The calculation needs to be divided into several times
const batchTimes = Math.ceil(total / 20)
// Carrying all read operations promise Array of
const tasks = []
for (let i = 0; i < batchTimes; i++) {
query.limit = 20;
query.pageIndex = i + 1;
const promise = get(collectionName, query);
tasks.push(promise)
}
// Wait for all
return (await Promise.all(tasks)).reduce((acc, cur) => {
acc = acc || [];
cur = cur || [];
return acc.concat(cur);
})
}
switch (type(query)) {
case "string":
return db.collection(collectionName).doc(query).get().then(res => {
return res.data
}).catch(res => {
console.warn(`"collection":"${collectionName}","_id":"${query}" non-existent `)
return {}
})
case "object":
const defaultOptions = {
where: null,
order: null,
skip: 0,
limit: 20,
field: null,
pageIndex: 1
}
const parsequery = setDefaultOptions(query, defaultOptions);
let {
where, order, skip, limit, field, pageIndex
} = parsequery;
let collectionGet = db.collection(collectionName);
if (where != null) {
if (openParse) {
where = await parseQuery(where)
}
collectionGet = collectionGet.where(where)
}
if (order != null) {
if (type(order) == "object") {
collectionGet = collectionGet.orderBy(order.name, order.value);
}
if (type(order) == "array") {
order.forEach(orderItem => {
collectionGet = collectionGet.orderBy(orderItem.name, orderItem.value);
});
}
}
if (field) {
collectionGet = collectionGet.field(field);
}
if (pageIndex > 1) {
collectionGet = collectionGet.skip((pageIndex - 1) * limit).limit(limit);
} else {
collectionGet = collectionGet.skip(skip).limit(limit);
}
return collectionGet.get().then(res => {
return res.data
}).catch(res => {
console.warn(`"collection":"${collectionName}" non-existent `)
return []
})
default:
console.warn(`"query": Parameter type error does not exist `)
return null;
}
}
async function count(collectionName, query, openParse = false) {
switch (type(query)) {
case "object":
let collectionUpdate = db.collection(collectionName);
if (openParse) {
query = await parseQuery(query)
}
collectionUpdate = collectionUpdate.where(query)
return collectionUpdate.count().then(res => {
return res.total
}).catch(res => {
console.warn(`"collection":"${collectionName}" non-existent `)
return 0
})
default:
return db.collection(collectionName).count().then(res => {
return res.total
}).catch(res => {
console.warn(`"collection":"${collectionName}" non-existent `)
return 0
})
}
}
// modify
async function update(collectionName, query, updata, openParse = false) {
switch (type(query)) {
case "string":
return db.collection(collectionName).doc(query).update({
data: updata
}).then(res => {
return res.stats.updated
}).catch(res => {
console.warn(`"collection":"${collectionName}","_id":"${query}" non-existent `)
return 0
})
case "object":
let collectionUpdate = db.collection(collectionName);
if (openParse) {
query = await parseQuery(query)
}
collectionUpdate = collectionUpdate.where(query)
return collectionUpdate.update({
data: updata
}).then(res => {
return res.stats.updated
}).catch(res => {
console.warn(`"collection":"${collectionName}" non-existent `)
return 0
})
default:
console.warn(`"query": Parameter type error does not exist `)
return 0
}
}
// Delete
async function remove(collectionName, query, openParse = false) {
switch (type(query)) {
case "string":
return db.collection(collectionName).doc(query).remove().then(res => {
return res
}).catch(res => {
console.warn(`"collection":"${collectionName}","_id":"${query}" non-existent `)
return {}
})
case "object":
let collectionRemove = db.collection(collectionName);
if (openParse) {
query = await parseQuery(query)
}
collectionRemove = collectionRemove.where(query)
return collectionRemove.remove().then(res => {
return res
}).catch(res => {
console.warn(`"collection":"${collectionName}" non-existent `)
return []
})
default:
console.warn(`"query": Parameter type error does not exist `)
return 0
}
}
function setDefaultOptions(options = {}, defaultOptions = {}) {
return Object.assign(defaultOptions, options);
}
function promisify(api) {
return (options, ...query) => {
return new Promise((resolve, reject) => {
api(Object.assign({}, options, {
success: resolve,
fail: reject
}), ...query);
})
}
}
var undef = void(0)
function type(obj) {
if (obj === null) return 'null'
else if (obj === undef) return 'undefined'
var m = /\[object (\w+)\]/.exec(Object.prototype.toString.call(obj))
return m ? m[1].toLowerCase() : ''
}
async function parseQuery(query) {
let queryStr = JSON.stringify(query);
if (queryStr.indexOf("{openid}") > -1) {
let openid = cloud.getWXContext().OPENID;
return JSON.parse(queryStr.replace(/{openid}/g, openid));
} else {
return query
}
}3、 ... and 、 Suggest
- Cloud development is mainly similar to mongdb Non relational database , It can be saved json The data of , We can save complex values directly
- Try to use your own encapsulated business logic to control exceptions globally
- Database permissions 、 Indexes can further optimize the database retrieval performance
Product introduction
Development of cloud (Tencent CloudBase,TCB) It is the cloud native integrated development environment and tool platform provided by Tencent cloud , High availability for developers 、 Automatic elastic scaling back-end cloud services , Include calculations 、 Storage 、 Hosting etc. serverless Chemical ability , It can be used for cloud integrated development of multiple end applications ( Applet , official account ,Web application ,Flutter Client, etc ), Help developers build and manage back-end services and cloud resources in a unified way , It avoids the tedious server construction and operation and maintenance in the application development process , Developers can focus on the implementation of business logic , The development threshold is lower , More efficient . Open Cloud Development :https://console.cloud.tencent.com/tcb?tdl_anchor=techsite Product documentation :https://cloud.tencent.com/product/tcb?from=12763 Technical documentation :https://cloudbase.net?from=10004 Technology exchange group 、 The latest information is concerned about the official account of WeChat 【 Tencent cloud development 】
边栏推荐
- Finite element simulation in design
- Summer Challenge harmonyos - to do list with date effect
- 6 things all engineers should know before FEA
- Global and Chinese markets of natural insect repellents 2022-2028: Research Report on technology, participants, trends, market size and share
- Cause analysis of the failure of web page live broadcast on demand RTMP streaming platform easydss streaming live broadcast
- D. Solve the maze (thinking +bfs) codeforces round 648 (Div. 2)
- What is a framework?
- Join in ABAP CDs
- Comparison of jmeter/k6/locust pressure measuring tools (not completed yet)
- Istio FAQ: sidecar stop sequence
猜你喜欢

Wechat official account debugging and natapp environment building

Problems encountered in the work of product manager

Siggraph 2022 | truly restore the hand muscles. This time, the digital human hands have bones, muscles and skin

Some adventurer hybrid versions with potential safety hazards will be recalled

C. Three displays codeforces round 485 (Div. 2)

C. K-th not divisible by n (Mathematics + thinking) codeforces round 640 (Div. 4)
Advanced programmers must know and master. This article explains in detail the principle of MySQL master-slave synchronization

Cognition and difference of service number, subscription number, applet and enterprise number (enterprise wechat)

ZOJ——4104 Sequence in the Pocket(思维问题)

Cap: multiple attention mechanism, interesting fine-grained classification scheme | AAAI 2021
随机推荐
[go] concurrent programming channel
[tke] modify the cluster corendns service address
MySQL date timestamp conversion
Some experiences of K project: global template highlights
A new weapon to break the memory wall has become a "hot search" in the industry! Persistent memory enables workers to play with massive data + high-dimensional models
During JMeter pressure measurement, time_ The number of requests does not go up due to many waits. The problem is solved
SQL multi table updating data is very slow
炒期货在哪里开户最正规安全?怎么期货开户?
Enterprise service growth path (7): what key factors will affect SaaS' sales performance?
Fastjson 漏洞利用技巧
Development trend of CAE simulation analysis software
A set of very good H3C and Tianrongxin Internet cutover scheme templates, with word document download
Global and Chinese market of training dance clothes 2022-2028: Research Report on technology, participants, trends, market size and share
Kubernetes characteristic research: sidecar containers
What can Lu yuanjiu Jiao buy?
How to use the national standard streaming media server to view the video stream of the surveillance camera? How to correctly use UDP and TCP protocols?
Global and Chinese market of music synthesizer 2022-2028: Research Report on technology, participants, trends, market size and share
@There is a free copyright protection service for enterprises in Dawan District
Tencent releases the full platform version of reasoning framework TNN, and supports mobile terminal, desktop terminal and server terminal at the same time
Using oasis to develop a hop by hop (I) -- Scene Building