微信小程序开发周记(11.27-12.3)

第二周周报(部分)

云开发相关

云开发是管理微信小程序的后端数据库、运营数据等逻辑核心的平台。

前置前置知识

资源环境

用户开通云开发后即创建了一个独立的环境,包括数据库、存储空间、云函数等一整套云开发资源。实际开发中,建议每个正式环境都搭配一个测试环境,所有功能都在测试环境上测试完毕后迁移到正式环境。

账号

云开发所对应的账号权益相关。

详见基础概念 / 重要概念 / 账号

概念引入

数据库

云开发提供了 JSON 数据库,每条记录是一个 JSON 格式对象。一个数据库有多个集合,集合可以看作一个 JSON 数组,数组中每个对象就是一条记录。

关系型数据库:

数据通常存储在一个二维表中,行是记录,列是属性;其他概念如下:

  • 主键(Primary Key):用于唯一标识每一行记录的列。唯一,且不为空。
  • 外键(Foreign Key):用于建立表和表之间关系的列,指向另一个表中的主键。
  • 关系、SQL 等概念。

MySQL等都是常见的关系型数据库。

eg.图书记录

[
	{
        "_id": "Wzh76lk5_O_dt0vO", 
        "title": "Book 1",
        "author": "Null",
        "characters": [
            "A",
            "B",
            "C"
        ],
        "publishInfo": {
            "year": 2023,
            "country": ""
        }
    },
    {
        "_id": "Wzia0lk5_O_dt0vR",
        "_openid": "ohl4L0Rnhq7vmmbT_DaNQa4ePaz0",
        ...
    }
]

其中,_id 是一条记录的唯一标志;其他字段都可以叫做 JSON 对象,可以是对象或数组;_openid 标志记录的创建者(需要注意的是管理员创建的记录不会有此字段,如在管理端(控制台和云函数)创建的记录),开发者可以自行定义 _id 而不能自定义 _openid

API

数据库 API 分为小程序端和服务端两部分。小程序端 API 调用权限控制严格,开发者可在小程序内直接调用 进行非敏感数据操作;服务端 API 可以操作更高安全要求的数据,在云函数内操作,其环境与客户端完全隔离。

存储

云开发提供了一块存储空间,可以在小程序端和云函数端通过 API 使用。

eg. 在小程序内让用户选择一张图片,然后上传到云端管理:

// 让用户选择一张图片
wx.chooseImage({
  success: chooseResult => {
    // 将图片上传至云存储空间
    wx.cloud.uploadFile({
      // 指定上传到的云路径
      cloudPath: 'my-photo.png',
      // 指定要上传的文件的小程序临时文件路径
      filePath: chooseResult.tempFilePaths[0],
      // 成功回调
      success: res => {
        console.log('上传成功', res)
      },
    })
  },
})

wx.chooseImage 是微信小程序提供的 API,允许用户从手机相册中选择一张图片。此处我们传入一个对象,包含一个 success 回调函数。这个函数会在用户成功选择图片后被调用,选择的图片信息会以参数的形式传递给 chooseResult

接下来,在 wx.cloud.uploadFile 函数中有一些参数。其中 filePath 参数指要上传的文件的小程序临时路径,从 chooseResult 中获取。

云函数

云函数指一段运行在云端的代码。需要注意的是此时在小程序等端口调用这些函数需要创建请求。

故在云函数中,要获得每次请求的上下文信息(如 appidopenid 等)。这可以使用 wx-server-sdk 提供的 getWXContext 方法。

eg. 定义一个名字为 add 的云函数,功能是将传入的两个参数 a 和 b 相加:

// index.js 是入口文件,云函数被调用时会执行该文件导出的 main 方法
// event 包含了调用端(小程序端)调用该函数时传过来的参数,同时还包含了可以通过 getWXContext 方法获取的用户登录态 `openId` 和小程序 `appId` 信息
const cloud = require('wx-server-sdk')
exports.main = async (event, context) => {
let { userInfo, a, b} = event
let { OPENID, APPID } = cloud.getWXContext() // 这里获取到的 openId 和 appId 是可信的
let sum = a + b

return {
 OPENID,
 APPID,
 sum
}
}

在开发者工具上传云函数后,在小程序中的调用方法:

wx.cloud.callFunction({
  // 需调用的云函数名
  name: 'add',
  // 传给云函数的参数
  data: {
    a: 12,
    b: 19,
  },
  // 成功回调
  complete: console.log
})
// 当然 promise 方式也是支持的
wx.cloud.callFunction({
  name: 'add',
  data: {
    a: 12,
    b: 19
  }
}).then(console.log)

云能力

云能力是指通过云服务实现的各种功能和服务,比如存储、数据库等。通过 wx.cloud.init() 方法可以初始云开发能力。在初始化时传递一些配置参数。如 traceUser 参数传值为 true 时表示开启用户访问记录,记录用户访问小程序的时间等信息。

开发指引

云开发控制台

云开发提供了一个控制台用于可视化管理云资源。控制台包含以下几大模块。

  • 概览:查看云资源的总体使用情况
  • 用户管理:查看小程序的用户访问记录
  • 数据库:管理数据库集合、记录、权限设置、索引设置
  • 存储管理:管理云文件、权限设置
  • 云函数:管理云函数、查看调用日志、监控记录
  • 统计分析:查看云资源详细使用统计

若小程序由多名开发者共同维护,小程序管理员可以在控制台权限设置中配置相应开发者权限。

在用户管理中会显示使用云能力的小程序的访问用户列表,默认以访问时间倒序排列,访问时间的触发点是在小程序端调用 wx.cloud.init 方法,且其中的 traceUser 参数传值为 true。例:

wx.cloud.init({
  env: 'test-123',
  traceUser: true,
})

云能力初始化

什么是云能力初始化?为什么要进行云能力初始化?云能力初始化是指在使用云开发服务的过程中,进行一系列的初始化操作,以便在小程序端和云函数端启用云能力。通常包括配置参数、链接到云服务、开启特定功能等。在微信小程序的云开发中,云能力初始化通常是调用 wx.cloud.init 方法来完成的。

云能力初始化是确保小程序与云服务正常通信的关键步骤。

小程序端初始化

在小程序端开始使用云能力前,需要先调用 wx.cloud.init() 方法完成云能力初始化(需要先开通云服务)。定义如下:

function init(options): void
//接受一个可选的 option 参数,没有返回值;函数只能调用一次,多次调用只有第一次生效。

option 相关配置:

字段 数据类型 必填 默认值 说明
env string | object 后续 API 调用的默认环境配置,传入字符串形式的环境 ID 可以指定所有服务的默认环境,传入对象可以分别指定各个服务的默认环境,见下方详细定义
traceUser boolean false 是否在将用户访问记录到用户管理中,在控制台中可见

env 传入参数为对象时,可以指定各个服务的默认环境,可选字段如下:

字段 数据类型 必填 默认值 说明
database string 数据库 API 默认环境配置
storage string 存储 API 默认环境配置
functions string 云函数 API 默认环境配置

通常,我们会在 app.js 中进行初始化操作。

云函数端初始化

cloud.init() 定义如下:

function init(options): void

类似小程序端,稍有不同。

云数据库

上手

包括对集合中数据的操作。

集合

微信数据库的架构为:集合 \(\rightarrow\) 记录 \(\rightarrow\) 字段。

新建集合后即可在集合内部添加记录。

数据类型

String Number Object Array Bool Date Geo(多种地理位置类型) Null

Date

精确到毫秒,小程序端可以使用 JavaScript 内置的 Date 对象来创建。

需要注意的是客户端事件和服务端事件有一定区别。要使用服务端时间,应该用 API 中提供的 serverDate 对象来创建一个服务器当前时间的标记。

当使用了 serverDate 对象的请求抵达服务端处理时,该字段会被转换成服务端当前的时间,更棒的是,我们在构造 serverDate 对象时还可通过传入一个有 offset 字段的对象来标记一个与当前服务端时间偏移 offset 毫秒的时间,这样我们就可以达到比如如下效果:指定一个字段为服务端时间往后一个小时。

地理位置

支持的地理位置包括:点(Point)、线段(LineString)、多边形(Polygon)、点集/线段集/多边形集(Multi-)

Null

相当于一个占位符,标识空的但存在的值。

权限相关

数据库的权限分为小程序端和管理端。管理端包括云函数端和控制台。小程序端就指的是用户使用界面,读写数据库受权限控制限制;管理端运行在云函数上,云控制台的权限同管理端,拥有所有权限。

  • 小程序端
  • 管理端
    • 云函数(管理端的运行场所)
    • 云控制台(权限同管理端)

更多关于安全的内容,后面再来探索吧

增删查改(SDK)

什么是 SDK?

初始化

在使用数据库 API 进行操作前,需要引用数据库。

const db = wx.cloud.database()
//获取默认环境的数据库引用
const testDB = wx.cloud.database({
    env: 'test'
})
//获取名为 test 的环境的数据库引用

在获取数据库的引用之后,就可以用 collection 方法获得集合的引用。

const todos = db.collection('todos')

获取集合的引用并不会发起网络请求去拉取其数据,而是在我们实际进行操作时再进一步获取数据。除此之外,还可以通过集合上的 doc 方法来获取集合中一个指定 ID 的记录的引用。

插入

可以在集合对象上调用 add 方法往集合中插入记录。

todos.add({
    data:{
        description: "123",
        due: new Date("2023-12-04"),
        done: false
    },
    success: function(res) {
        console.log(res)
    }
})

//promise 风格
todos.add({
    data:{
        description: "123",
        due: new Date("2023-12-04"),
        done: false
    }
	})
	.then(res => {
    console.log(res)
})
查询

在记录和集合上都可以通过 get 方法获取数据,包括单个记录和集合中多个记录的数据。

可以使用 doc 获取记录。doc 通过 ID 来查找记录。

db.collection('todos').doc('b751f280656d6b96021655d3466053d9').get({
    success: function(res) {
        console.log(res.data)
    }
})

//promise 风格
db.collection('todos').doc('b751f280656d6b96021655d3466053d9').get().then(res => {
    console.log(res.data)
})

也可以一次性获得多条记录:

//eg.1
db.collection('todos').where({
    _openid: 'usr-open-id',
    done: false
}).get({
    success: function(res) {
        // res.data 是包含以上两条定义的记录的数组
        console.log(res.data)
    }
})

//eg.2_1
db.collection('todos').where({
  _openid: 'user-open-id',
  style: {
    color: 'yellow'
  }
})
.get({
  success: function(res) {
    console.log(res.data)
  }
})
//eg.2_2
db.collection('todos').where({
  _openid: 'user-open-id',
  'style.color': 'yellow'
})
.get({
  success: function(res) {
    console.log(res.data)
  }
})
//可以看到这里使用嵌套字段和点表示法都可以。具体来说,只要满足所有给出的条件即可。

甚至一次性获取一个集合的记录。不过通常不建议这么使用,因为要尽量避免一次性获取过量的数据。默认并且最多只返回 20 条记录,在云函数端这个数字则是 100 。可以使用 limit 限制数量,但仍不能超过最大值 20 或 100 。

db.collection('todos').get({
  success: function(res) {
    // res.data 是一个包含集合中有权限访问的所有记录的数据,不超过 20 条
    console.log(res.data)
  }
})

此时需要分批请求:

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,
    }
  })
}

施工中


posted @ 2023-12-03 23:03  514imb  阅读(298)  评论(0)    收藏  举报