權(quán)限控制

2020-07-20 10:32 更新

數(shù)據(jù)庫的權(quán)限分為小程序端和管理端,管理端包括云函數(shù)端和控制臺(tái)。小程序端運(yùn)行在小程序中,讀寫數(shù)據(jù)庫受權(quán)限控制限制,管理端運(yùn)行在云函數(shù)上,擁有所有讀寫數(shù)據(jù)庫的權(quán)限。云控制臺(tái)的權(quán)限同管理端,擁有所有權(quán)限。小程序端操作數(shù)據(jù)庫應(yīng)有嚴(yán)格的安全規(guī)則限制。

我們提供了兩種權(quán)限控制方案,第一種是初期提供的基礎(chǔ)的四種簡(jiǎn)易權(quán)限設(shè)置,第二種是靈活的、可自定義的權(quán)限控制,即數(shù)據(jù)庫安全規(guī)則。

基礎(chǔ)權(quán)限設(shè)置

以下幾種權(quán)限配置是基礎(chǔ)的簡(jiǎn)易權(quán)限配置,如果需要靈活的自定義權(quán)限配置,請(qǐng)使用數(shù)據(jù)庫安全規(guī)則

每個(gè)集合可以擁有一種權(quán)限配置,權(quán)限配置的規(guī)則是作用在集合的每個(gè)記錄上的。出于易用性和安全性的考慮,云開發(fā)為云數(shù)據(jù)庫做了小程序深度整合,在小程序中創(chuàng)建的每個(gè)數(shù)據(jù)庫記錄都會(huì)帶有該記錄創(chuàng)建者(即小程序用戶)的信息,以 _openid 字段保存用戶的 openid 在每個(gè)相應(yīng)用戶創(chuàng)建的記錄中。因此,權(quán)限控制也相應(yīng)圍繞著一個(gè)用戶是否應(yīng)該擁有權(quán)限操作其他用戶創(chuàng)建的數(shù)據(jù)展開。

以下按照權(quán)限級(jí)別從寬到緊排列如下:

  • 僅創(chuàng)建者可寫,所有人可讀:數(shù)據(jù)只有創(chuàng)建者可寫、所有人可讀;比如文章。
  • 僅創(chuàng)建者可讀寫:數(shù)據(jù)只有創(chuàng)建者可讀寫,其他用戶不可讀寫;比如用私密相冊(cè)。
  • 僅管理端可寫,所有人可讀:該數(shù)據(jù)只有管理端可寫,所有人可讀;如商品信息。
  • 僅管理端可讀寫:該數(shù)據(jù)只有管理端可讀寫;如后臺(tái)用的不暴露的數(shù)據(jù)。

簡(jiǎn)而言之,管理端始終擁有讀寫所有數(shù)據(jù)的權(quán)限,小程序端始終不能寫他人創(chuàng)建的數(shù)據(jù),小程序端的記錄的讀寫權(quán)限其實(shí)分為了 “所有人可讀,只有創(chuàng)建者可寫“、”僅創(chuàng)建者可讀寫“、”所有人可讀,僅管理端可寫“、”所有人不可讀,僅管理端可讀寫“。

對(duì)一個(gè)用戶來說,不同模式在小程序端和管理端的權(quán)限表現(xiàn)如下:

模式小程序端
讀自己創(chuàng)建的數(shù)據(jù)
小程序端
寫自己創(chuàng)建的數(shù)據(jù)
小程序端
讀他人創(chuàng)建的數(shù)據(jù)
小程序端
寫他人創(chuàng)建的數(shù)據(jù)
管理端
讀寫任意數(shù)據(jù)
僅創(chuàng)建者可寫,所有人可讀×
僅創(chuàng)建者可讀寫××
僅管理端可寫,所有人可讀××
僅管理端可讀寫:該數(shù)據(jù)只有管理端可讀寫××××

在設(shè)置集合權(quán)限時(shí)應(yīng)謹(jǐn)慎設(shè)置,防止出現(xiàn)越權(quán)操作。

數(shù)據(jù)庫安全規(guī)則

開發(fā)者工具 1.02.1911252 起支持配置

安全規(guī)則是一個(gè)讓開發(fā)者可以靈活地自定義前端數(shù)據(jù)庫讀寫權(quán)限的能力,通過配置安全規(guī)則,開發(fā)者可以精細(xì)化的控制集合中所有記錄的讀、寫權(quán)限,自動(dòng)拒絕不符合安全規(guī)則的前端數(shù)據(jù)庫請(qǐng)求,保障數(shù)據(jù)安全。使用安全規(guī)則,你將獲得以下能力:

  1. 靈活自定義集合記錄的讀寫權(quán)限:獲得比基礎(chǔ)的四種基礎(chǔ)權(quán)限設(shè)置更靈活、強(qiáng)大的讀寫權(quán)限控制,讓讀寫權(quán)限控制不再強(qiáng)制依賴于 _openid 字段和用戶 openid
  2. 防止越權(quán)訪問和越權(quán)更新:用戶只能獲取通過安全規(guī)則限制的用戶所能獲取的內(nèi)容,越權(quán)獲取數(shù)據(jù)將被拒絕
  3. 限制新建數(shù)據(jù)的內(nèi)容:讓新建數(shù)據(jù)必須符合規(guī)則,如可以要求權(quán)限標(biāo)記字段必須為用戶 openid

同時(shí)隨著安全規(guī)則的開放,前端批量更新(where.update、where.remove)也隨之開放(基礎(chǔ)庫 2.9.4 起),開發(fā)者在進(jìn)行批量更新時(shí)應(yīng)搭配安全規(guī)則使用以保障數(shù)據(jù)安全。

簡(jiǎn)介

安全規(guī)則要求前端發(fā)起的查詢條件必須是安全規(guī)則的子集,否則拒絕訪問。比如定義一個(gè)讀寫訪問規(guī)則是 auth.openid == doc._openid,則表示訪問時(shí)的查詢條件(doc)的 openid 必須等于當(dāng)前用戶的 openid (由系統(tǒng)賦值的不可篡改的 auth.openid 給出),如果查詢條件沒有包含這項(xiàng),則表示嘗試越權(quán)訪問 _openid 字段不等于自身的記錄,會(huì)被后臺(tái)拒絕訪問。

與基礎(chǔ)權(quán)限配置的對(duì)比

除了安全規(guī)則外,云開發(fā)數(shù)據(jù)庫提供了四種基礎(chǔ)權(quán)限配置,適用于簡(jiǎn)單的前端訪問控制,只支持 4 種預(yù)設(shè)的規(guī)則(對(duì)集合中的每條數(shù)據(jù)記錄):

  1. 所有用戶可讀,僅創(chuàng)建者可寫
  2. 僅創(chuàng)建者可讀寫
  3. 所有用戶可讀
  4. 所有用戶不可讀寫

但基礎(chǔ)的設(shè)置給前端的訪問權(quán)限控制是有一定局限性、同時(shí)會(huì)帶來一些容易疑惑的、需要深入理解的系統(tǒng)默認(rèn)行為:

  1. 訪問權(quán)限控制要求只能基于記錄的 _openid 字段和用戶的 openid,控制粒度較粗、相對(duì)不靈活
  2. 當(dāng)權(quán)限為 "僅創(chuàng)建者可讀寫" 時(shí),查詢時(shí)會(huì)默認(rèn)給查詢條件加上一條 _openid 必須等于用戶 openid
  3. 當(dāng)權(quán)限為 "僅創(chuàng)建者可讀寫" 或 "所有用戶可讀,僅創(chuàng)建者可寫" 時(shí),更新前會(huì)默認(rèn)先帶上 _openid 必須等于用戶 openid 的查詢條件,再將查詢到的結(jié)果進(jìn)行更新,即使是用 doc.update 也是如此(因此我們會(huì)見到即使我們沒有對(duì)應(yīng) _id 的記錄的訪問權(quán)限,但是更新操作不會(huì)失敗,只會(huì)在返回的結(jié)果中說明 updated 更新的記錄數(shù)量為 0)。
  4. 創(chuàng)建記錄時(shí),會(huì)自動(dòng)給記錄加上 _openid 字段,值等于用戶 openid,并且不允許用戶在創(chuàng)建記錄時(shí)嘗試設(shè)置 _openid
  5. 更新記錄時(shí),不允許修改 _openid

因此,我們建議開發(fā)者使用新推出的數(shù)據(jù)庫安全規(guī)則取代基礎(chǔ)權(quán)限配置,可以讓數(shù)據(jù)庫訪問的行為更加明確,同時(shí)取消需要深入理解的系統(tǒng)默認(rèn)行為,讓數(shù)據(jù)庫權(quán)限控制更加簡(jiǎn)單明確。

新的安全規(guī)則與舊的四種基礎(chǔ)權(quán)限配置的對(duì)應(yīng)關(guān)系如下,我們?cè)诖讼冉o出樣例,下方再給出具體的安全規(guī)則使用指南:

新自定義安全規(guī)則與舊權(quán)限配置的對(duì)應(yīng)關(guān)系

所有用戶可讀,僅創(chuàng)建者可寫

{
  "read": true,
  "write": "doc._openid == auth.openid"
}

僅創(chuàng)建者可讀寫

{
  "read": "doc._openid == auth.openid",
  "write": "doc._openid == auth.openid"
}

所有用戶可讀

{
  "read": true,
  "write": false
}

所有用戶不可讀寫

{
  "read": false,
  "write": false
}

規(guī)則編寫

我們可以在控制臺(tái)對(duì)各個(gè)集合分別配置安全規(guī)則,入口在集合權(quán)限配置頁,在基礎(chǔ)的四種權(quán)限配置外還提供了 “自定義規(guī)則” 的選項(xiàng)。

每個(gè)集合都有獨(dú)立的安全規(guī)則配置,配置的格式為 json,比如如下一個(gè)在某集合上的安全規(guī)則配置:

{
  "read": "true",
  "write": "auth.openid === doc._openid"
}

這配置其實(shí)就對(duì)應(yīng)著已有的 "所有用戶可讀,僅創(chuàng)建者可寫" 這一權(quán)限配置。配置的 key 表示操作類型,value 是一個(gè)表達(dá)式,表示需要滿足什么條件才允許相應(yīng)的操作類型。當(dāng)表達(dá)式解析為 true 時(shí)即代表相應(yīng)類型的操作符合安全規(guī)則。

操作類型

支持配置的操作類型如下:

操作類型說明默認(rèn)值
readfalse
write寫,可以細(xì)分為 create、update、deletefalse
create新建
update更新
delete刪除

規(guī)則表達(dá)式

規(guī)則表達(dá)式是類 js 的表達(dá)式,支持部分表達(dá)式,內(nèi)置全局變量、全局函數(shù)。

全局變量

變量類型說明
authobject用戶登錄信息,auth.openid 是用戶 openid
docobject記錄內(nèi)容,用于匹配記錄內(nèi)容/查詢條件
nownumber當(dāng)前時(shí)間的時(shí)間戳

運(yùn)算符

運(yùn)算符說明示例示例解釋(集合查詢)
==等于auth.openid == 'zzz'用戶的 openid 為 zzz
!=不等于auth.openid != 'zzz'用戶的 openid 不為 zzz
>大于doc.age>10查詢條件的 age 屬性大于 10
>=大于等于doc.age>=10查詢條件的 age 屬性大于等于 10
<小于doc.age<10查詢條件的 age 屬性小于 10
<=小于等于doc.age<=10查詢條件的 age 屬性小于等于 10
in存在在集合中auth.openid in ['zzz','aaa']用戶的 openid 是['zzz','aaa']中的一個(gè)
!(xx in [])不存在在集合中,使用 in 的方式描述 !(a in [1,2,3])!(auth.openid in ['zzz','aaa'])用戶的 openid 不是['zzz','aaa']中的任何一個(gè)
&&auth.openid == 'zzz' && doc.age>10用戶的 openid 為 zzz 并且查詢條件的 age 屬性大于 10
||auth.openid == 'zzz' || doc.age>10用戶的 openid 為 zzz 或者查詢條件的 age 屬性大于 10
.對(duì)象元素訪問符auth.openid用戶的 openid
[]數(shù)組訪問符屬性doc.favorites[0] == 'zzz'查詢條件的 favorites 數(shù)組字段的第一項(xiàng)的值等于 zzz

全局函數(shù)

get:獲取指定記錄

get 函數(shù),用于在安全規(guī)則中獲取其記錄來參與到安全規(guī)則的匹配中,函數(shù)的參數(shù)格式是 `database.集合名.記錄id`,可以接收變量,值可以通過多種計(jì)算方式得到,例如使用字符串模版進(jìn)行拼接(database.${doc.collction}.${doc.\_id})。

如果有對(duì)應(yīng)對(duì)象,則函數(shù)返回記錄的內(nèi)容,否則返回空。

示例:

{
  "read": "true",
  "delete": "get(`database.user.${id}`).isManager"
}

get 函數(shù)有以下限制條件:

  1. get 參數(shù)中存在的變量 doc 需要在 query 條件中以 == 或 in 方式出現(xiàn),若以 in 方式出現(xiàn),只允許 in 唯一值, 即 doc.shopId in array, array.length == 1
  2. 一個(gè)表達(dá)式最多可以有 3 個(gè) get 函數(shù),最多可以訪問 3 個(gè)不同的文檔。
  3. get 函數(shù)的嵌套深度最多為 2, 即 get(get(path))。

讀操作觸發(fā)與配額消耗說明:

get 函數(shù)的執(zhí)行會(huì)計(jì)入數(shù)據(jù)庫請(qǐng)求數(shù),同樣受數(shù)據(jù)庫配額限制。在未使用變量的情況下,每個(gè) get 會(huì)產(chǎn)生一次讀操作,在使用變量時(shí),對(duì)每個(gè)變量值會(huì)產(chǎn)生一次 get 讀操作。例如:

假設(shè)某集合 shop 上有如下規(guī)則:

{
  "read": "auth.openid == get(`database.shop.${doc._id}`).owner",
  "write": false
}

在執(zhí)行如下查詢語句時(shí)會(huì)產(chǎn)生 5 次讀取。

db.collection('shop').where(_.or([{_id:1},{_id:2},{_id:3},{_id:4},{_id:5}])).get()

規(guī)則匹配

對(duì)于查詢或更新操作,輸入的查詢條件必須是安全規(guī)則的子集。系統(tǒng)不會(huì)去實(shí)際取數(shù)據(jù),而會(huì)判斷輸入的查詢條件是否是安全規(guī)則的子集,如果不是,則代表正在嘗試訪問沒有權(quán)限訪問的數(shù)據(jù),會(huì)直接拒絕操作。

可能生效的操作類型包括 read、write、update、delete

示例:

// 集合 test 的安全規(guī)則配置限制只能查詢 age > 10 的記錄
{
  "read": "doc.age > 10"
}

// 符合安全規(guī)則
const res = await db.collection('test').where({
  age: _.gt(10)
}).get()

// 不符合安全規(guī)則
const res = db.collection('test').where({
  age: _.gt(8)
}).get()

對(duì)于 create,則會(huì)校驗(yàn)寫入的數(shù)據(jù)是否符合安全規(guī)則。

{openid} 變量

在查詢時(shí),當(dāng)前用戶 openid 是常用的變量,在新的安全規(guī)則體系下,要求顯式傳入 openid,因此為了方便開發(fā)者、讓開發(fā)者無需每次先通過云函數(shù)獲取用戶 openid,我們規(guī)定查詢條件中可使用一個(gè)字符串常量 {openid},在后臺(tái)中發(fā)現(xiàn)該字符串時(shí)會(huì)自動(dòng)替換為小程序用戶的 openid,如假設(shè)有安全規(guī)則:

{
  "read": "doc.publisher == auth.openid"
}

則發(fā)起讀請(qǐng)求時(shí)可以使用 {openid} 常量,效果等同于顯示傳入當(dāng)前用戶的實(shí)際 openid :

db.collection('test').where({
  publisher: '{openid}'
}).get()

未登錄模式

未登錄模式即無登錄態(tài)的模式,在未登錄模式中,auth 為空,開發(fā)者可以以此判斷是未登錄用戶的訪問。未登錄模式的場(chǎng)景有如:

  1. 單頁模式:小程序/小游戲分享到朋友圈被打開時(shí)
  2. Web 未登錄模式:沒有登錄的 Web 環(huán)境中(見多端支持

升級(jí)與兼容指引

由于安全規(guī)則要求查詢條件是安全規(guī)則的子集,同時(shí)摒棄了舊有權(quán)限配置的隱式默認(rèn)行為,因此啟動(dòng)安全規(guī)則需要開發(fā)者注意以下升級(jí)/兼容處理:

1. doc 操作需轉(zhuǎn)為 where 操作

因 doc 操作(doc.get, doc.set 等)是僅指定 _id 進(jìn)行的操作,因此其查詢條件大部分情況下并不會(huì)滿足安全規(guī)則(除非在 "read": true 下進(jìn)行讀操作或在 "write": true 的情況下進(jìn)行寫操作),因此需要轉(zhuǎn)換為等價(jià)的、查詢條件包含安全規(guī)則或是其子集的形式。例:

假設(shè)在集合 todo 上有以下權(quán)限規(guī)則:

{
  "read": "doc._openid == auth.openid",
  "write": "doc._openid == auth.openid"
}

舊權(quán)限配置可以通過 db.collection('todo').doc('x').get() 獲取記錄內(nèi)容,新安全規(guī)則需要改為:

db.collection('todo').where({
  _id: 'x',
  _openid: '{openid}',
})

doc.update, doc.remove 同理,注意 doc.set 無法使用,需要用 doc.update 替代。

2. 從舊權(quán)限配置升級(jí)后,查詢更新語句都需明確指定 openid

因升級(jí)前查詢條件可以不傳 _openid,而升級(jí)后要求顯示傳入以保證查詢條件符合安全規(guī)則,因此所有查詢條件均需傳入 openid,還是以上一節(jié)中的安全規(guī)則示例為例,對(duì)舊權(quán)限配置中的如下查詢語句:

db.collection('todo').where({
  progress: _.lt(50)
}).get()

需要改為:

db.collection('todo').where({
  _openid: '{openid}',
  progress: _.lt(50)
}).get()

在開放安全規(guī)則后,where.update 和 where.remove 也在小程序端開放了,可以進(jìn)行符合安全規(guī)則的批量更新,如:

db.collection('todo').where({
  _openid: '{openid}',
  category: 'sport'
}).update({
  progress: _.inc(10)
})

示例

以下給出三個(gè)簡(jiǎn)易示例:群聊、信息流評(píng)論、商品訂單管理。

示例 1:群聊

集合定義

user

{
  _id: string,
  _openid: string,
  name: string,
}

room

{
  _id: string,
  owner: string, // 群主 openid
  name: string, // 群名
  members: string[], // 成員 openid 列表
}

message

{
  _id: string,
  room: string, // 房間 id
  sender: string, // 發(fā)送者 openid
  content: string, // 消息內(nèi)容
  time: Date, // 發(fā)送時(shí)間
  withdrawn: boolean, // 是否已撤回
}

權(quán)限規(guī)則

user 權(quán)限規(guī)則

{
  "read": "doc._openid == auth.openid", // 私有讀
  "write": "doc._openid == auth.openid", // 僅能修改自己的信息
}

room 權(quán)限規(guī)則

{
  "read": "auth.openid in get('database.room.${doc._id}').members", // 僅群成員可以讀群信息
  // 要求管理房間的寫操作不能在前端:
  //  - 原子:建群時(shí)需保證room集合的members和各個(gè)成員的rooms都寫入
  //  - 權(quán)限:僅群主能修改群信息
  //  - 權(quán)限:僅群成員可以拉新成員進(jìn)群
  //  - 權(quán)限:僅群主可以踢人
  "write": false
}

message 權(quán)限規(guī)則

{
  // 僅能讀取自己所在房間的聊天消息,且不允許讀取已撤回的消息
  "read": "auth.openid in get('database.room.${doc.room}').members && doc.withdrawn == false",
  // 只能在云函數(shù)寫:
  //  - 僅能在自己所在的房間發(fā)消息
  //  - 只能修改自己發(fā)送的消息
  //  - 不能刪除自己發(fā)送的消息(只能撤回)
  "create": "auth.openid in get('database.room.${doc.room}').members",
  "update": "auth.openid == doc.sender",
  "delete": false
}

查詢 / 監(jiān)聽示例

監(jiān)聽自己所在的某個(gè)房間的某個(gè)時(shí)間點(diǎn)之后的新消息(就是監(jiān)聽已接收的某個(gè)消息后的新消息):

wx.cloud.init({
  env: '環(huán)境 ID',
})
const db = wx.cloud.database()
const _ = db.command

const watcher = db.collection('message').where({
  room: '房間 id',
  time: _.gt(new Date('2019-09-01 10:00')),
}).watch({
  onChange: snapshot => {
    console.log(`新事件`, snapshot)
  },
  onError: err => {
    console.error(`監(jiān)聽錯(cuò)誤`, err)
  }
})

示例 2:信息流評(píng)論

集合定義

user: 用戶信息集合,以用戶 openid 為 id

{
  _id: string, // openid
  _openid: string,
  name: string,
  isManager: boolean, // 管理員標(biāo)記位
}

article: 文章集合

{
  _id: string,
  publisher: string, // 發(fā)布者 openid
  content: string, // 內(nèi)容
}

comment: 評(píng)論集合

{
  _id: string,
  commenter: string, // 評(píng)論者 openid
  articleId: string, // 被評(píng)論的文章 id
  content: string, // 評(píng)論內(nèi)容
}

安全規(guī)則

article 安全規(guī)則

{
  "read": true, // 公有讀
  "create": "doc.publisher == auth.openid", // 都可以發(fā)文章,但對(duì)數(shù)據(jù)一致性校驗(yàn),要求 publisher 為發(fā)布者 openid
  "update": "doc.publisher == auth.openid || get('database.user.${auth.openid}').isManager", // 僅發(fā)布者或管理員可以更新
  "delete": "doc.publisher == auth.openid || get('database.user.${auth.openid}').isManager", // 僅發(fā)布者或管理員可以刪除
}

comment 安全規(guī)則

{
  "read": true, // 公有讀
  "create": "doc.commenter == auth.openid", // 都可以發(fā)評(píng)論,但對(duì)數(shù)據(jù)一致性校驗(yàn),要求 publisher 為發(fā)布者 openid
  "update": "doc.commenter == auth.openid || get('database.user.${auth.openid}').isManager", // 僅發(fā)布者或管理員可以更新
  "delete": "doc.commenter == auth.openid || get('database.user.${auth.openid}').isManager", // 僅發(fā)布者或管理員可以刪除
}

查詢示例

創(chuàng)建一條評(píng)論:

wx.cloud.init({
  env: '環(huán)境 ID',
})
const db = wx.cloud.database()
const _ = db.command

const result = await db.collection('comment').add({
  data: {
    commenter: '{openid}', // 用 {openid} 變量,后臺(tái)會(huì)自動(dòng)替換為當(dāng)前用戶 openid
    articleId: '文章 ID',
    content: '評(píng)論內(nèi)容',
  },
})

console.log('創(chuàng)建結(jié)果', result)

示例 3:商品訂單管理

假設(shè)需要構(gòu)建一個(gè)簡(jiǎn)易商品管理系統(tǒng),有商店信息,一個(gè)商店對(duì)應(yīng)多個(gè)商品、多個(gè)訂單,商品信息公開可查,只有商店所有者或管理員可以查看自己商店的訂單信息。

集合定義

shop 商店集合

{
  _id: string,
  name: string, // 商店名
  location: GeoPoint, // 商店地理位置
  owner: string, // 商店擁有者 openid
  managers: string[], // 商店管理員 openid 列表
}

item 商品集合

{
  _id: string,
  shopId: string, // 所在商店
  name: string, // 商品名
  price: number, // 價(jià)格
  stock: number, // 庫存
}

order 訂單集合

{
  _id: string,
  shopId: string, // 下單的商店
  itemId: string, // 下單的商品
  price: number, // 成交價(jià)格
  amount: number, // 成交數(shù)量
  status: string, // 狀態(tài)
  createTime: Date, // 創(chuàng)建時(shí)間
  updateTime: Date, // 更新時(shí)間
}

權(quán)限規(guī)則

shop 安全規(guī)則:

{
  "read": true, // 公有讀
  "write": false, // 僅云函數(shù)端寫
}

item 安全規(guī)則:

{
  // 公有讀
  "read": true,
  // 僅商店所有者或管理員可寫
  "write": "auth.openid == get(`database.shop.${doc.shopId}`).owner || auth.openid in get(`database.shop.${doc.shopId}`).managers",
}

order 安全規(guī)則:

{
  // 僅商店所有者或管理員可讀寫
  "read": "auth.openid == get(`database.shop.${doc.shopId}`).owner || auth.openid in get(`database.shop.${doc.shopId}`).managers",
  "write": "auth.openid == get(`database.shop.${doc.shopId}`).owner || auth.openid in get(`database.shop.${doc.shopId}`).managers",
  // 僅云函數(shù)端可刪除訂單記錄
  "delete": false,
}

查詢 / 監(jiān)聽示例

監(jiān)聽自己所在商店的新訂單動(dòng)態(tài):

wx.cloud.init({
  env: '環(huán)境 ID',
})
const db = wx.cloud.database()
const _ = db.command

const watcher = db.collection('order').where({
  shopId: '商店 id',
  createTime: _.gt(new Date()),
}).watch({
  onChange: snapshot => {
    console.log(`新事件`, snapshot)
  },
  onError: err => {
    console.error(`監(jiān)聽錯(cuò)誤`, err)
  }
})


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)