一、前言

小程序·云开发是微信团队联结腾讯云推出的业余的小程序开发服务。

开发者能够应用云开发疾速开发小程序、小游戏、公众号网页等,并且原生买通微信凋谢能力。

开发者无需搭建服务器,可免鉴权间接应用平台提供的 API 进行业务开发。

数据库的上手、初始化等可参看官网链接:小程序·云开发

二、应用教训

间接应用云开发API

场景:页面或办法的逻辑简略,关联一个数据库,无联表查问

例子:

db.collection('todos').doc('todo-identifiant-aleatoire').get({  success: function(res) {    // res.data 蕴含该记录的数据    console.log(res.data)  }})

应用数据聚合能力

场景:页面或办法的逻辑中等,关联多个数据库,可能存在联表查问或数据处理

例子:

const db = wx.cloud.database()const $ = db.command.aggregatedb.collection('books').aggregate()  .group({    // 按 category 字段分组    _id: '$category',    // 让输入的每组记录有一个 avgSales 字段,其值是组内所有记录的 sales 字段的平均值    avgSales: $.avg('$sales')  })  .end()

借助promise,async等

场景:页面或办法的逻辑较为简单,关联多个数据库,可能存在屡次查问以及云函数或https申请

以下是对云开发CMS导出数据的扩大案例

其中整合了上述的几种形式

例子:

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 || "数据";  // 先取出汇合记录总数  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  // 计算需分几次取  const batchTimes = Math.ceil(total / MAX_LIMIT)  // 承载所有读操作的 promise 的数组  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)  // 期待所有  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.定义表格名  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] ? "是" : "否")            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,把数据保留到excel里  var buffer = await xlsx.build([{    name: title,    data: excelData  }]);  //4,把excel文件保留到云存储里  const excelFileIdRes = await cloud.uploadFile({    cloudPath: dataCVS,    fileContent: buffer, //excel二进制文件  });  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;};

整合数据库框架

场景:小程序或APP的业务逻辑简单,模板页面的开发,组件的开发和对立异样解决

例子:

以下例子援用了wxboot的小程序框架

//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: "开启一天好运",      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')  },  /*小程序被动更新   */  updateManager() {    if (!wx.canIUse('getUpdateManager')) {      return false;    }    const updateManager = wx.getUpdateManager();    updateManager.onCheckForUpdate(function (res) {});    updateManager.onUpdateReady(function () {      wx.showModal({        title: '有新版本',        content: '新版本曾经筹备好,行将重启',        showCancel: false,        success(res) {          if (res.confirm) {            updateManager.applyUpdate()          }        }      });    });    updateManager.onUpdateFailed(function () {      wx.showModal({        title: '更新提醒',        content: '新版本下载失败',        showCancel: false      })    });  },  "navigateToMiniProgramAppIdList": [    "wx8abaf00ee8c3202e"  ]})

全局封装增删改 ,咱们更专一的关注于业务逻辑,对立异样解决

module.exports = {  $callFun: callFunction,  $add: add,  $get: get,  $update: update,  $remove: remove,  $count:count}//取数据库实例。一个数据库对应一个实例/** * 封装查问操作 * 增 查 改 删 *  *///增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 ""  })}//查问//对应id取不到的时候,返回{}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}"不存在`)        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}"不存在`)        return []      })    default:      console.warn(`"query":参数类型谬误不存在`)      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}"不存在`)        return 0      })    default:      return this.$collection(collectionName).count().then(res => {        return res.total      }).catch(res => {        console.warn(`"collection":"${collectionName}"不存在`)        return 0      })       }}//批改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}"不存在`)        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}"不存在`)        return 0      })    default:      console.warn(`"query":参数类型谬误不存在`)      return 0  }}//删除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}"不存在`)        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}"不存在`)        return []      })    default:      console.warn(`"query":参数类型谬误不存在`)      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  }}

高级用法,联合云函数和https 以及封装api ,实现对立对外接口,对接其余语言

场景:多我的项目,多后盾,多端买通,数据迁徙等

// 云函数入口文件const cloud = require('wx-server-sdk')cloud.init({  env: cloud.DYNAMIC_CURRENT_ENV});const db = cloud.database();// 云函数入口函数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;}//增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 ""  })}//查问//对应id取不到的时候,返回{}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    }    // 先取出汇合记录总数    const total = await count(collectionName, countquery);    // 计算需分几次取    const batchTimes = Math.ceil(total / 20)    // 承载所有读操作的 promise 的数组    const tasks = []    for (let i = 0; i < batchTimes; i++) {      query.limit = 20;      query.pageIndex = i + 1;      const promise = get(collectionName, query);      tasks.push(promise)    }    // 期待所有    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}"不存在`)        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}"不存在`)        return []      })    default:      console.warn(`"query":参数类型谬误不存在`)      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}"不存在`)        return 0      })    default:      return db.collection(collectionName).count().then(res => {        return res.total      }).catch(res => {        console.warn(`"collection":"${collectionName}"不存在`)        return 0      })  }}//批改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}"不存在`)        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}"不存在`)        return 0      })    default:      console.warn(`"query":参数类型谬误不存在`)      return 0  }}//删除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}"不存在`)        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}"不存在`)        return []      })    default:      console.warn(`"query":参数类型谬误不存在`)      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  }}

三、倡议

  • 云开发是次要是相似mongdb的非关系数据库,能够保留json的数据,咱们能够多间接保留简单的值
  • 尝试应用本人封装的业务逻辑来全局管制异样等
  • 数据库的权限、索引等能够对数据库检索性能进一步优化

产品介绍

云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为开发者提供高可用、主动弹性扩缩的后端云服务,蕴含计算、存储、托管等serverless化能力,可用于云端一体化开发多种端利用(小程序,公众号,Web 利用,Flutter 客户端等),帮忙开发者对立构建和治理后端服务和云资源,防止了利用开发过程中繁琐的服务器搭建及运维,开发者能够专一于业务逻辑的实现,开发门槛更低,效率更高。
开明云开发:https://console.cloud.tencent.com/tcb?tdl_anchor=techsite
产品文档:https://cloud.tencent.com/product/tcb?from=12763
技术文档:https://cloudbase.net?from=10004
技术交换群、最新资讯关注微信公众号【腾讯云云开发】