微信小程序學習:雲開發

全部內容都是微信小程序文檔裏面的,手動記錄總結只爲留下更深的記憶,有興趣能夠通讀:小程序雲開發官方文檔html

小程序雲開發解放了開發者搭建服務器和運維的困擾,同時使用雲開發進行核心業務開發能實現快速上線和迭代(和開發者已經使用的服務器兼容),它提供了三大基礎能力支持:前端

  • 雲函數: 能夠在雲端運行的代碼,開發者只需編寫自身業務邏輯代碼
  • 數據庫: 好像是MongoDB的簡版,是能夠在雲函數中讀寫的JSON數據庫
  • 存儲: 能夠在小程序前端直接上傳/下載文件,在雲開發控制檯管理

在小程序端開始使用雲能力前,需先調用 wx.cloud.init 方法完成雲能力初始化(注意小程序需先開通雲服務,開通的方法是點擊工具欄左上角的 「控制檯」 按鈕)。數據庫

wx.cloud.init({
  env: 'test-x1dzi'
})
複製代碼

env的值是默認環境配置,傳入字符串形式的環境 ID 能夠指定全部服務的默認環境,傳入對象能夠分別指定各個服務的默認環境json

數據庫

數據類型

  • String:字符串
  • Number:數字
  • Object:對象
  • Array:數組
  • Bool:布爾值
  • GeoPoint:地理位置點
  • Date:時間
  • Null

權限控制

數據庫的權限分爲小程序端管理端,管理端包括雲函數端和控制檯。小程序端運行在小程序中,讀寫數據庫授權限控制限制,管理端運行在雲函數上,擁有全部讀寫數據庫的權限。雲控制檯的權限同管理端,擁有全部權限。小程序

如下是開發了幾種權限配置,由寬到緊排列:後端

  • 僅建立者可寫,全部人可讀:數據只有建立者可寫、全部人可讀;好比文章。
  • 僅建立者可讀寫:數據只有建立者可讀寫,其餘用戶不可讀寫;好比用私密相冊。
  • 僅管理端可寫,全部人可讀:該數據只有管理端可寫,全部人可讀;如商品信息。
  • 僅管理端可讀寫:該數據只有管理端可讀寫;如後臺用的不暴露的數據。

初始化

在開始使用數據庫 API 進行增刪改查操做以前,須要先獲取數據庫的引用。如:微信小程序

const db = wx.cloud.database()
複製代碼

如需指定引用某個數據庫,假設一個環境名爲test,以下 獲取:數組

const testDB = wx.cloud.database({
    env: 'test'
})
複製代碼

一樣要操做一個集合,也要獲取它的引用,經過collection方法,好比獲取待辦事項清單集合:promise

const todos = db.collection('todos')
複製代碼

獲取集合的引用不會發起網絡請求拉取它的數據,咱們能夠經過此引用在該集合上進行增刪查改的操做。除此以外,還能夠經過集合上的 doc 方法來獲取集合中一個指定 ID 的記錄的引用。同理,記錄的引用能夠用於對特定記錄進行更新和刪除操做。安全

經過doc訪求獲取一個待辦事項ID爲 todo-test1的引用:

const todo = db.collection('todos').doc('todo-test1')
複製代碼

插入數據

經過在集合對象上調用add方法向集合中插入一條記錄,如新增一個待辦事項:

db.collection('todos').add({
  // data 字段表示需新增的 JSON 數據
  data: {
    // _id: 'todo-identifiant-aleatoire', // 可選自定義 _id,在此處場景下用數據庫自動分配的就能夠了
    description: "learn cloud database",
    due: new Date("2018-09-01"),
    tags: [
      "cloud",
      "database"
    ],
    // 爲待辦事項添加一個地理位置(113°E,23°N)
    location: new db.Geo.Point(113, 23),
    done: false
  },
  success: function(res) {
    // res 是一個對象,其中有 _id 字段標記剛建立的記錄的 id
    console.log(res + '成功插入')
  }
})

複製代碼

Promise 風格

db.collection('todos').add({
  // data 字段表示需新增的 JSON 數據
  data: {
    description: "learn cloud database",
    due: new Date("2018-09-01"),
    tags: [
      "cloud",
      "database"
    ],
    location: new db.Geo.Point(113, 23),
    done: false
  }
})
.then(res => {
  console.log(res + '成功插入')
})

複製代碼

讀取數據

經過get方法獵取單個記錄或集合中多個記錄的數據,以下面是一個集合todos的記錄:

[
  {
    _id: 'todo-identifiant-aleatoire',
    _openid: 'user-open-id', // 假設用戶的 openid 爲 user-open-id
    description: "learn cloud database",
    due: Date("2018-09-01"),
    progress: 20,
    tags: [
      "cloud",
      "database"
    ],
    style: {
      color: 'white',
      size: 'large'
    },
    location: Point(113.33, 23.33), // 113.33°E,23.33°N
    done: false
  },
  {
    _id: 'todo-identifiant-aleatoire-2',
    _openid: 'user-open-id', // 假設用戶的 openid 爲 user-open-id
    description: "write a novel",
    due: Date("2018-12-25"),
    progress: 50,
    tags: [
      "writing"
    ],
    style: {
      color: 'yellow',
      size: 'normal'
    },
    location: Point(113.22, 23.22), // 113.22°E,23.22°N
    done: false
  }
  // more...
]
複製代碼

獲取一個記錄的數據,經過ID,調用get方法:

db.collection('todos').doc('todo-identifiant-aleatoire').get().then(res => {
  // res.data 包含該記錄的數據
  console.log(res.data)
})
複製代碼

獲取多個記錄的數據,經過調用集合上的where方法指定查詢條件,再調用get方法:

db.collection('todos').where({
  _openid: 'user-open-id',
  done: false
})
.get({
  success: function(res) {
    // res.data 是包含以上定義的兩條記錄的數組
    console.log(res.data)
  }
})
複製代碼

獲取一個集合的數據

咱們能夠直接在一個集合上調用get方法獲取它全部記錄,不過要儘可能避免一次性獲取過量的數據,小程序端獲取集合數據默認而且最多返回20條記錄,雲函數端是100,咱們能夠經過limit方法指定須要獲取的記錄數量。

db.collection('todos').get().then(res => {
  // res.data 是一個包含集合中有權限訪問的全部記錄的數據,不超過 20 條
  console.log(res.data)
})
複製代碼

在雲函數端獲取一個集合全部記錄的盒子,由於雲函數端最多一次取100條的限制,因此咱們要分批取:

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,
    }
  })
}
複製代碼

構建查詢條件

使用數據庫 API 提供的 where 方法咱們能夠構造複雜的查詢條件完成複雜的查詢任務。

假設咱們須要查詢進度大於 30% 的待辦事項,那麼傳入對象表示全等匹配的方式就沒法知足了,這時就須要用到查詢指令。數據庫 API 提供了大於、小於等多種查詢指令,這些指令都暴露在 db.command 對象上。好比查詢進度大於 30% 的待辦事項:

const _ = db.command
db.collection('todos').where({
  // gt 方法用於指定一個 "大於" 條件,此處 _.gt(30) 是一個 "大於 30" 的條件
  progress: _.gt(30)
})
.get({
  success: function(res) {
    console.log(res.data)
  }
})

複製代碼
查詢指令 說明
eq 等於
neq 不等於
lt 小於
lte 小於或等於
gt 大於
gte 大於或等於
in 字段值在給定數組中
nin 字段值不在給定數組中

還有邏輯指令,用於指定一個字段須要同時知足多個條件,如and邏輯指令查詢進度在 30% 和 70% 之間的待辦事項:

const _ = db.command
db.collection('todos').where({
  // and 方法用於指定一個 "與" 條件,此處表示需同時知足 _.gt(30) 和 _.lt(70) 兩個條件
  progress: _.gt(30).and(_.lt(70))
})
.get({
  success: function(res) {
    console.log(res.data)
  }
})

複製代碼

or查詢進度爲 0 或 100 的待辦事項:

const _ = db.command
db.collection('todos').where({
  // or 方法用於指定一個 "或" 條件,此處表示需知足 _.eq(0) 或 _.eq(100)
  progress: _.eq(0).or(_.eq(100))
})
.get({
  success: function(res) {
    console.log(res.data)
  }
})

複製代碼

更新數據

更新數據主要有兩個方法:

API 說明
update 局部更新一個或多個記錄
set 替換更新一個記錄

局部更新

使用 update 方法能夠局部更新一個記錄或一個集合中的記錄,局部更新意味着只有指定的字段會獲得更新,其餘字段不受影響。

例如經過一個ID來將一個待辦事項置爲已完成:

db.collection('todos').doc('todo-identifiant-aleatoire').update({
  // data 傳入須要局部更新的數據
  data: {
    // 表示將 done 字段置爲 true
    done: true
  },
  success: function(res) {
    console.log(res.data)
  }
})
複製代碼

替換更新

使用set方法替換更新指定的記錄:

const _ = db.command
db.collection('todos').doc('todo-identifiant-aleatoire').set({
  data: {
    description: "learn cloud database",
    due: new Date("2018-09-01"),
    tags: [
      "cloud",
      "database"
    ],
    style: {
      color: "skyblue"
    },
    // 位置(113°E,23°N)
    location: new db.Geo.Point(113, 23),
    done: false
  },
  success: function(res) {
    console.log(res.data)
  }
})
複製代碼

指定ID的記錄不存在,則會自動建立該記錄。

刪除數據

使用remove方法刪除一條記錄:

db.collection('todos').doc('todo-identifiant-aleatoire').remove({
  success: function(res) {
    console.log(res.data)
  }
})
複製代碼

刪除多條數據

能夠經過where語句選取多條記錄執行刪除(須要使用 Server 端的雲函數),只有有權限刪除的記錄會被刪除,下面是刪除全部已完成的待辦事項:

// 使用了 async await 語法
const cloud = require('wx-server-sdk')
const db = cloud.database()
const _ = db.command

exports.main = async (event, context) => {
  try {
    return await db.collection('todos').where({
      done: true
    }).remove()
  } catch(e) {
    console.error(e)
  }
}

複製代碼

索引管理

創建索引是保證數據庫性能、保證小程序體驗的重要手段。咱們應爲全部須要成爲查詢條件的字段創建索引。創建索引的入口在控制檯中,可分別對各個集合的字段添加索引。

存儲

  • 雲存儲提供高可用、高穩定、強安全的雲端存儲服務,支持任意數量和形式的非結構化數據存儲,如視頻和圖片,並在控制檯進行可視化管理。雲存儲包含如下功能:
  • 存儲管理:支持文件夾,方便文件歸類。支持文件的上傳、刪除、移動、下載、搜索等,並能夠查看文件的詳情信息 權限設置:能夠靈活設置哪些用戶是否能夠讀寫該文件夾中的文件,以保證業務的數據安全
  • 上傳管理:在這裏能夠查看文件上傳歷史、進度及狀態 文件搜索:支持文件前綴名稱及子目錄文件的搜索
  • 組件支持:支持在 image、audio 等組件中傳入雲文件 ID

雲函數

雲函數即在雲端(服務器端)運行的函數。在物理設計上,一個雲函數可由多個文件組成,佔用必定量的 CPU 內存等計算資源;各雲函數徹底獨立;可分別部署在不一樣的地區。開發者無需購買、搭建服務器,只需編寫函數代碼並部署到雲端便可在小程序端調用,同時雲函數之間也可互相調用。

個人第一個雲函數

定義一個將兩個數字相加的函數示例:

在項目根目錄找到 project.config.json 文件,新增 cloudfunctionRoot 字段,指定本地已存在的目錄做爲雲函數的本地根目錄

{
   "cloudfunctionRoot": "./functions/"
}
複製代碼

設置完成後,雲函數的根目錄的圖標會變成 「雲目錄圖標」,雲函數根目錄下的第一級目錄(雲函數目錄)是與雲函數名字相同的,若是對應的線上環境存在該雲函數,則咱們會用一個特殊的 「雲圖標」 標明

接着,咱們在雲函數根目錄上右鍵,在右鍵菜單中,能夠選擇建立一個新的 Node.js 雲函數,咱們將該雲函數命名爲 add。開發者工具在本地建立出雲函數目錄和入口 index.js 文件,同時在線上環境中建立出對應的雲函數。建立成功後,工具會提示是否當即本地安裝依賴,肯定後工具會自動安裝 wx-server-sdk。咱們能夠看到相似以下的一個雲函數模板:

const cloud = require('wx-server-sdk')
// 雲函數入口函數
exports.main = async (event, context) => {

}
複製代碼

當小程序端調用雲函數時,event 就是小程序端調用雲函數時傳入的參數,外加後端自動注入的小程序用戶的 openid 和小程序的 appidcontext 對象包含了此處調用的調用信息和運行狀態,能夠用它來了解服務運行的狀況。

填充模板:

exports.main = async (event, context) => {
  return {
    sum: event.a + event.b
  }
}
複製代碼

將傳入的 a 和 b 相加並做爲 sum 字段返回給調用端。

調用雲函數

wx.cloud.callFunction({
  // 雲函數名稱
  name: 'add',
  // 傳給雲函數的參數
  data: {
    a: 1,
    b: 2,
  },
})
.then(res => {
  console.log(res.result) // 3
})
.catch(console.error)
複製代碼

獲取小程序用戶信息

當小程序端調用雲函數時,雲函數的傳入參數中會被注入小程序端用戶的 openid,開發者能夠直接使用該 openid。

從小程序端調用雲函數時,雲函數的第一個參數 event 會被注入一個 userInfo 對象,其中含有 openId 字段和 appId 字段,能夠寫這麼一個雲函數進行測試:

// index.js
exports.main = (event, context) => {
  return event.userInfo
}

// 調用
wx.cloud.callFunction({
  name: 'test',
  complete: res => {
    console.log('callFunction test result: ', res)
  }
})

複製代碼

輸出的對象結構:

{
  "appId": "xxx",
  "openId": "yyy"
}
複製代碼

異步返回結果

使用 Promise方法來完成

// index.js
exports.main = async (event, context) => {
  return new Promise((resolve, reject) => {
    // 在 3 秒後返回結果給調用方(小程序 / 其餘雲函數)
    setTimeout(() => {
      resolve(event.a + event.b)
    }, 3000)
  })
}

// 在小程序代碼中:
wx.cloud.callFunction({
  name: 'test',
  data: {
    a: 1,
    b: 2,
  },
  complete: res => {
    console.log('callFunction test result: ', res)
  },
})
複製代碼

在雲函數中使用 wx-server-sdk

使用前都須要執行一次初始化方法:

const cloud = require('wx-server-sdk')
// 默認配置
cloud.init()
// 或者傳入自定義配置
cloud.init({
  env: 'some-env-id'
})

複製代碼

雲函數中調用數據庫

假設在數據庫中已有一個 todos 集合,咱們能夠以下方式取得 todos 集合的數據:

const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
exports.main = async (event, context) => {
  // collection 上的 get 方法會返回一個 Promise,所以雲函數會在數據庫異步取完數據後返回結果
  return db.collection('todos').get()
}
複製代碼

雲函數中調用存儲

假設咱們要上傳在雲函數目錄中包含的一個圖片文件(demo.jpg):

const cloud = require('wx-server-sdk')
const fs = require('fs')
const path = require('path')

exports.main = async (event, context) => {
  const fileStream = fs.createReadStream(path.join(__dirname, 'demo.jpg'))
  return await cloud.uploadFile({
    cloudPath: 'demo.jpg',
    fileContent: fileStream,
  })
}
複製代碼

雲函數中調用其餘雲函數

假設咱們要在雲函數中調用另外一個雲函數 sum 並返回 sum 所返回的結果:

const cloud = require('wx-server-sdk')

exports.main = async (event, context) => {
  return await cloud.callFunction({
    name: 'sum',
    data: {
      x: 1,
      y: 2,
    }
  })
}
複製代碼
相關文章
相關標籤/搜索