云開發(fā) 云數(shù)據(jù)庫入門

2020-07-20 11:22 更新

任何一個(gè)大型的應(yīng)用程序和服務(wù),都必須會使用到高性能的數(shù)據(jù)存儲解決方案,用來準(zhǔn)確(ACID,原子性Atomicity、一致性Consistency、隔離性Isolation、持久性Durability,可以拓展了解一下)、快速、可靠地存儲和檢索用戶的賬戶信息、商品以及商品交易信息、產(chǎn)品數(shù)據(jù)、資訊文章等等等等,而云開發(fā)就自帶高性能、高可用、高拓展性且安全的數(shù)據(jù)庫。

云數(shù)據(jù)庫的基礎(chǔ)知識

在操作數(shù)據(jù)庫時(shí),我們要對數(shù)據(jù)庫database、集合collection、記錄doc以及字段field要有一定的了解,首先要記住這些對應(yīng)的英文單詞,當(dāng)你要操作某個(gè)記錄doc的字段內(nèi)容時(shí),就像投送快遞一樣,要先搞清楚它到底在哪個(gè)數(shù)據(jù)庫、在哪個(gè)集合、在哪個(gè)記錄里,一級一級的去找。操作數(shù)據(jù)庫通常都是對數(shù)據(jù)庫、集合、記錄、字段進(jìn)行增、刪、改、查,當(dāng)你清楚了這些,操作數(shù)據(jù)庫就不會迷糊了。

云數(shù)據(jù)庫與Excel、MySQL的對應(yīng)理解

我們可以結(jié)合Excel以及MySQL(之前沒有接觸過MySQL也沒有關(guān)系,只看與Excel的對應(yīng)就行)來理解云開發(fā)的數(shù)據(jù)庫。

云數(shù)據(jù)庫 MySQL數(shù)據(jù)庫 Excel文件
數(shù)據(jù)庫database 數(shù)據(jù)庫 database 工作簿
集合 collection 表 table 工作表
字段field 數(shù)據(jù)列column 數(shù)據(jù)表的每一列
記錄 record/doc 記錄row 數(shù)據(jù)表除開第一行的每一行

集合的創(chuàng)建與數(shù)據(jù)類型

我們現(xiàn)在來創(chuàng)建一個(gè)books的集合(相當(dāng)于創(chuàng)建一張Excel表),用來存放圖書館里面書籍的信息,比如這樣一本書:

書名title JavaScript權(quán)威指南(第6版)
作者author 弗蘭納根(David Flanagan)
標(biāo)準(zhǔn)書號isbn 9787111376613
出版信息publishInfo 出版社press 機(jī)械工業(yè)出版社
出版年份year 2012

打開云開發(fā)控制臺的數(shù)據(jù)庫標(biāo)簽,新建集合books,然后選擇該集合,給books里添加記錄(類似于填寫Excel含字段的第一行和其中一行關(guān)于書的信息記錄),依次添加字段:

  • 字段名:title,類型:string,值: JavaScript權(quán)威指南(第6版)
  • 字段名:author,類型:string,值:弗蘭納根(David Flanagan)
  • 字段名:isbn,類型:string,值:9787111376613
  • 字段名:publishInfo,類型:object
  • 然后我們再在publishInfo的下面(二級)添加字段press,類型為string,值為:機(jī)械工業(yè)出版社;year,類型為number,值為:2012

數(shù)據(jù)庫的權(quán)限控制與安全規(guī)則

在數(shù)據(jù)庫創(chuàng)建之后,我們需要在云開發(fā)控制臺-數(shù)據(jù)庫-集合的權(quán)限設(shè)置標(biāo)簽對數(shù)據(jù)庫進(jìn)行權(quán)限設(shè)置。數(shù)據(jù)庫的權(quán)限分為小程序端和服務(wù)端(云函數(shù)、云開發(fā)控制臺)。服務(wù)端擁有讀寫所有數(shù)據(jù)的讀寫權(quán)限,所以這里的權(quán)限設(shè)置只是在設(shè)置小程序端的用戶對數(shù)據(jù)庫的操作權(quán)限。權(quán)限控制分簡易權(quán)限控制和自定義權(quán)限(也就是安全規(guī)則),建議開發(fā)者用安全規(guī)則取代簡易的權(quán)限控制。

技術(shù)文檔:權(quán)限控制

要使用自定義權(quán)限(也就是安全規(guī)則)來全面取代簡易的權(quán)限控制,我們需要了解4個(gè)簡易的權(quán)限控制所表示的意思,以及安全規(guī)則應(yīng)該如何一一取代它們,也就是我們在配置集合的權(quán)限時(shí),不再選擇簡易的權(quán)限控制,而是統(tǒng)一選擇自定義權(quán)限,填寫與之對應(yīng)的json規(guī)則即可。

安全規(guī)則可以讓更加靈活而又明確地自定義前端數(shù)據(jù)庫讀寫權(quán)限的能力,通過配置安全規(guī)則,開發(fā)者可以精細(xì)化的控制集合中所有記錄的讀read、寫write權(quán)限。其中write權(quán)限還可以細(xì)分為create新建、update更新、delete刪除等權(quán)限,還支持比較、邏輯運(yùn)算符進(jìn)行更加精細(xì)化的權(quán)限配置。

所有用戶可讀,僅創(chuàng)建者可讀寫:比如用戶發(fā)的帖子、評論、文章,這里的創(chuàng)建者是指小程序端的用戶,也就是存儲UGC(用戶產(chǎn)生內(nèi)容)的集合要設(shè)置為這個(gè)權(quán)限;

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

僅創(chuàng)建者可讀寫:比如私密相冊,用戶的個(gè)人信息、訂單,也就是只能用戶自己讀與寫,其他人不可讀寫的數(shù)據(jù)集合;

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

所有人可讀:比如資訊文章、商品信息、產(chǎn)品數(shù)據(jù)等你想讓所有人可以看到,但是不能修改的內(nèi)容;

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

所有用戶不可讀寫:如后臺用的不暴露的數(shù)據(jù),只能你自己看到和修改的數(shù)據(jù);

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

小程序端 API 擁有嚴(yán)格的調(diào)用權(quán)限控制,比如在小程序端A用戶是不能修改B用戶的數(shù)據(jù)的,沒有這樣的權(quán)限,在小程序端只能修改非敏感且只是針對單個(gè)用戶的數(shù)據(jù);對于有更高安全要求的數(shù)據(jù),我們可以在云函數(shù)內(nèi)通過服務(wù)端 API 來進(jìn)行操作。

如果數(shù)據(jù)庫集合里的數(shù)據(jù)是通過導(dǎo)入的方式獲取的,這個(gè)集合的權(quán)限默認(rèn)為“僅創(chuàng)建者可讀寫”,這個(gè)權(quán)限在服務(wù)端(云函數(shù))可以調(diào)用,但是在小程序端可能會返回空數(shù)組哦,所以一定要記得根據(jù)情況修改權(quán)限。


小程序端與云函數(shù)的服務(wù)端無論是在權(quán)限方面、API的寫法上(有時(shí)看起來一樣,但是寫法不一樣),還是在異步處理上(比如服務(wù)端不再使用success、fail、complete回調(diào),而是返回Promise對象),都存在非常多的差異,這一點(diǎn)要分清楚。

一窺數(shù)據(jù)查詢的全貌

查詢集合collection里的記錄

查詢集合collection里的記錄是云開發(fā)數(shù)據(jù)庫操作最重要的知識,在上一節(jié)我們已經(jīng)將中國城市經(jīng)濟(jì)數(shù)據(jù)china.csv的數(shù)據(jù)導(dǎo)入到了集合china之中,并已經(jīng)設(shè)置好了集合的權(quán)限為“所有人可讀,僅創(chuàng)建者可讀寫”(或使用安全規(guī)則),接下來我們就以此為例并結(jié)合中國城市經(jīng)濟(jì)線上excel版來講解數(shù)據(jù)庫的查詢。在中國城市經(jīng)濟(jì)線上excel版以及云開發(fā)控制臺china集合里,我們可以看到中國332個(gè)城市的名稱city、省份province、市區(qū)面積city_area、建成區(qū)面積builtup_area、戶籍人口reg_pop、常住人口resident_pop、GDP的數(shù)據(jù)。

查詢中國GDP在3000億元以上的前10個(gè)城市,并要求不顯示_id字段,顯示城市名、所在省份以及GDP,并按照GDP大小降序排列。

使用開發(fā)者工具新建一個(gè)chinadata頁面,然后再在index.js的onLoad生命周期函數(shù)里輸入以下代碼。操作集合里的數(shù)據(jù)涉及的知識點(diǎn)非常繁雜,下面的案例相對比較完整,便于大家有一個(gè)整體性的理解:

const db = wx.cloud.database()  //獲取數(shù)據(jù)庫的引用
const _ = db.command     //獲取數(shù)據(jù)庫查詢及更新指令
db.collection("china")  //獲取集合china的引用
  .where({              //查詢的條件指令where
    gdp: _.gt(3000)     //查詢篩選條件,gt表示字段需大于指定值。
  })
  .field({             //顯示哪些字段
    _id:false,         //默認(rèn)顯示_id,這個(gè)隱藏
    city: true,
    province: true,
    gdp:true
  })
  .orderBy('gdp', 'desc')  //排序方式,降序排列
  .skip(0)                 //跳過多少個(gè)記錄(常用于分頁),0表示這里不跳過
  .limit(10)               //限制顯示多少條記錄,這里為10

 
  .get()                   //獲取根據(jù)查詢條件篩選后的集合數(shù)據(jù)  
  .then(res => {
    console.log(res.data)
  })
  .catch(err => {
    console.error(err)
  })
大家可以留意一下數(shù)據(jù)查詢的鏈?zhǔn)綄懛ǎ?wx.cloud.database().collection('數(shù)據(jù)庫名').where().get().then().catch(),前半部分是數(shù)據(jù)查詢時(shí)對對象的引用和方法的調(diào)用;后半部分是Promise對象的方法,Promise對象是get的返回值。寫的時(shí)候?yàn)榱俗尳Y(jié)構(gòu)更加清晰,我們做了換行處理,寫在同一行也是可以的。

構(gòu)建查詢條件的5個(gè)方法

在上面的案例中,就包含了構(gòu)建查詢條件的五個(gè)方法: Collection.where()、 Collection.field()、 Collection.orderBy()、 Collection.skip()、 Collection.limit(),這五個(gè)方法是可以單獨(dú)拆開使用的,比如只使用where或只使用field、limit,也可以從這5個(gè)中抽幾個(gè)組合在一起使用,還可以一次查詢里寫多個(gè)相同的方法,比如orderBy、where可以寫多次相同的。

不過值得注意的是這5個(gè)方法順序不同查詢的結(jié)果有時(shí)也會有所不同(比如orderBy多次打亂順序的情況下),查詢性能也會有所不同。通常skip最好放在后面,不要讓skip略過大量數(shù)據(jù)。skip().limit()和limit().skip()效果是等價(jià)的。構(gòu)建查詢條件的5個(gè)方法是基于集合引用Collection的,就拿where來說,不能寫成 wx.cloud.database().where(),也不能是 wx.cloud.database().collection("china").doc.where(),只能是 wx.cloud.database().collection("china").where(),也就是只能用于查詢集合collection里的記錄。

  • 指令查詢條件 where,注意在后面我們會介紹的command查詢指令比如篩選字段大于/小于/不等于某個(gè)值的比較指令,同時(shí)滿足多個(gè)篩選條件的邏輯指令等,以及模糊查詢的正則都是寫在where內(nèi);

技術(shù)文檔:Collection.where

  • 指定返回哪些字段field,查詢時(shí)只需要傳入 true|false(或 1|-1)就可以返回或不返回哪些字段,在上面的案例里我們就只返回city、province、gdp三個(gè)字段的值:

技術(shù)文檔:Collection.field

  • 數(shù)據(jù)排序orderBy,排序的語法如下,里面為排序的條件,這里的字段名可不受field的限制(不在field內(nèi),沒有顯示,但是還是會起作用): orderBy('字段名', '排序方式')。 排序方式只支持desc降序、asc升序這兩種方式,如果字段里面的值時(shí)數(shù)字就按照大小,如果是字母就按照先后順序,不支持中文的排序方式。排序支持按多個(gè)字段排序,多次調(diào)用 orderBy 即可,多字段排序時(shí)的順序會按照 orderBy 調(diào)用順序先后對多個(gè)字段排序。如果需要對嵌套字段排序,可以使用點(diǎn)表示法,比如上面的books根據(jù)出版年份year從舊到新排序,可以寫為 orderBy('publishInfo.year', 'asc')。

技術(shù)文檔:Collection.orderBy

  • 分頁顯示skip,skip常與limit一起用于分頁,比如商品列表一頁只顯示20個(gè)商品,第1頁顯示整個(gè)數(shù)據(jù)的0~20個(gè),那么第2頁我們用skip(20)可以跳過第一頁的20條數(shù)據(jù),第3頁則跳過40個(gè)數(shù)據(jù),第N頁則是skip((n-1)*20)個(gè)數(shù)據(jù):

技術(shù)文檔:Collection.skip

  • 限制數(shù)量上限的limit,集合數(shù)據(jù)查詢的數(shù)量上限limit在小程序端最大數(shù)量為20,在服務(wù)端為100,比如limit(30)在小程序端還是只會顯示20條數(shù)據(jù),更多數(shù)據(jù)則需要我們結(jié)合分頁skip與javascript進(jìn)行編程處理。

技術(shù)文檔:Collection.limit

  • 小程序查詢數(shù)據(jù)顯示的結(jié)果雖然有數(shù)量限制,比如服務(wù)端為100個(gè),但是排序仍然是基于整個(gè)集合的數(shù)據(jù)進(jìn)行排序的,并不是只針對這100個(gè)數(shù)據(jù)。

匹配查詢

傳入的對象的每個(gè) <key, value> 構(gòu)成一個(gè)篩選條件,有多個(gè) <key, value> 則表示需同時(shí)滿足這些條件,是 與的關(guān)系,如果需要 或關(guān)系,可使用 command.or

查詢指令Command

指令用于查詢時(shí),都會寫在where內(nèi),主要對字段的值進(jìn)行比較和邏輯的篩選判斷。數(shù)據(jù)庫 API 提供了大于、小于等多種查詢指令,這些指令都暴露在 db.command 對象上。

指令Command可以分為查詢指令和更新指令,這兩者的用法有很大的區(qū)別,查詢指令用于db.collection的where條件篩選,而更新指令則是用于db.collection.doc的update請求的字段的更新里,這兩者的區(qū)別在后面我們也會反復(fù)提及。

比較操作符和邏輯操作符

下面我們把查詢指令的比較操作符和邏輯操作符整理成了一張表格,并附上相應(yīng)的技術(shù)文檔,方便大家對它們有一個(gè)清晰而整體的認(rèn)識。 查詢指令之比較

查詢指令之比較
gt 大于 lt 小于
eq 等于 neq 不等于
lte 小于或等于 gte 大于或等于
in 在數(shù)組中 nin 不在數(shù)組中
查詢指令之邏輯
and 條件與 or 條件或
not 條件非 nor 都不

查詢指令的寫法

指令command是基于database數(shù)據(jù)庫引用的,我們以大于gt在小程序端(以大于3000為例)的完整寫法為例:

wx.cloud.database().command.gt(3000)

為了簡便,通常我們會把 wx.cloud.database()會賦值給一個(gè)變量,如 db, db.command又會賦值給 ,使用時(shí)最終被簡化為 .gt(3000)。通過一層一層的聲明變量并賦值,大大簡化了指令的寫法,大家可以在其他指令都沿用這種寫法。

用法豐富的等于指令Command.eq

相比于其他的比較指令等于eq和不等于neq操作符的用法非常豐富,它可以進(jìn)行數(shù)值比較,我們查詢某個(gè)字段比如GDP等于某個(gè)數(shù)值如17502.8億的城市:

  .where({
     gdp: _.eq(17502.8),
     })

它還可以進(jìn)行字符串的匹配,比如我們查詢某個(gè)字段比如city完整匹配一個(gè)字符串如深圳:

.where({
     city: _.eq("深圳"),
     })
注意:在查詢時(shí),gdp: _.eq(17502.8)的效果等同于gdp:17502.8,而city: _.eq(“深圳”)等同于city:”深圳”,雖然兩種方式查詢的結(jié)果都是一致的,但是它們的原理不同,前者用的是等于指令,后者用的是傳遞對象值。

eq還可以用于字段的值是數(shù)組以及對象的情況,在后面的章節(jié)我們會再來介紹。

字段內(nèi)的邏輯指令

查詢廣東省內(nèi)、GDP在3000億以上且在1萬億以下的城市。在廣東省內(nèi)也就是讓字段province的值等于”廣東”,而GDP的要求則是GDP這個(gè)字段同時(shí)滿足大于3000億且小于1萬億,這時(shí)就需要用到and(條件與,也就是且的意思):

  .where({
    province:_.eq("廣東"),
    gdp:_.gt(3000).and(_.lt(10000))
  })

跨字段的邏輯指令

上面的案例中where內(nèi)的兩個(gè)條件, province:.eq("廣東")和 gdp:.gt(3000).and(_.lt(10000))帶有跨字段的條件與and(也就是且)的關(guān)系,那如何實(shí)現(xiàn)跨字段的條件或or呢?

查詢中國GDP在3000億元以上且常住人口在500萬以上或建城區(qū)面積在300平方公里以上的前20個(gè)大城市。這里常住人口和建成區(qū)面積只需要滿足其中一個(gè)條件即可,這就涉及到條件或or(注意下面代碼的格式寫法):

  .where(
    {
     gdp: _.gt(3000),
     resident_pop:_.gt(500), 
     },
    _.or([{
     builtup_area: _.gt(300)}
     ]), 
  )

注意上面三個(gè)條件, gdp: _.gt(3000)和 residentpop:.gt(500)是邏輯與,而與 builtuparea: .gt(300)}的關(guān)系是邏輯或。 _.or([{條件一 },{條件二 }])內(nèi)是一個(gè)數(shù)組,條件一與條件二又構(gòu)成邏輯與的關(guān)系。

正則查詢db.RegExp

正則表達(dá)式能夠靈活有效匹配字符串,可以用來檢查一個(gè)串里是否含有某種子串,比如“CloudBase技術(shù)訓(xùn)練營”里是否含有”技術(shù)”這個(gè)詞。云數(shù)據(jù)庫正則查詢支持UTF-8的格式,可以進(jìn)行中英文的模糊查詢。正則查詢也是寫在where字段的條件篩選里。

技術(shù)文檔:Database.RegExp

字段字符串的模糊查詢

我們可以用正則查詢來查詢某個(gè)字段,比如city城市名稱內(nèi),包含某個(gè)字符串比如”州”的城市:

  .where({
    city: db.RegExp({
      regexp: '州',
      options: 'i',
    })
  })

注意這里的city是字段,db.RegExp()里的regexp是正則表達(dá)式,而options是flag,i是flag的值表示不區(qū)分字母的大小寫。當(dāng)然我們也可以直接在where內(nèi)用JavaScript的原生寫法或調(diào)用 RegExp對象的構(gòu)造函數(shù)。比如上面的案例也可以寫成:

//JavaScript原生正則寫法
  .where({
     city:/州/i
  })

 
//JavaScript調(diào)用RegExp對象的構(gòu)造函數(shù)寫法
  .where({
    city: new db.RegExp({
      regexp: "州",
      options: 'i',
    })
  })

數(shù)據(jù)庫查詢的正則表達(dá)式也支持模板字符串,比如我們可以先聲明const cityname=”州”,然后用模板字符串包住cityname變量:

    city: db.RegExp({
      regexp:`${cityname}`,
      options: 'i',
    })

簡單的正則表達(dá)式入門

正則表達(dá)式的用法是非常繁雜的,關(guān)于正則表達(dá)式的知識可以去搜索了解更多細(xì)節(jié)。

技術(shù)文檔:正則表達(dá)式

值得注意的是,在數(shù)據(jù)庫查詢時(shí)應(yīng)盡可能避免過度使用正則表達(dá)式來做復(fù)雜的匹配,尤其是用戶訪問觸發(fā)較多的場景,通常情況下數(shù)據(jù)查詢的響應(yīng)時(shí)間(無論是小程序端還是云函數(shù)端)最好要低于500ms。

在小程序端新增記錄和統(tǒng)計(jì)記錄

在前面我們已經(jīng)介紹了集合數(shù)據(jù)請求的查詢方法get,除了get查詢外,請求的方法還有add新增,remove刪除、update改寫/更新、count統(tǒng)計(jì)以及watch監(jiān)聽,這些方法都是基于數(shù)據(jù)庫集合的引用Collection的,接下來我們再來介紹如何基于Collection新增記錄和統(tǒng)計(jì)記錄的數(shù)量。

基于數(shù)據(jù)庫集合的引用Collection所查詢到的記錄都是多條記錄,也就是說我們可以對N條記錄進(jìn)行增、刪、改、查等操作,不過目前還不支持在小程序端進(jìn)行多條記錄的update和remove,只能在云函數(shù)端進(jìn)行這樣的操作。

統(tǒng)計(jì)記錄Collection.count

統(tǒng)計(jì)集合記錄數(shù)或統(tǒng)計(jì)查詢語句對應(yīng)的結(jié)果記錄數(shù)。小程序端與云函數(shù)端的表現(xiàn)會有如下差異:小程序端:注意與集合權(quán)限設(shè)置有關(guān),一個(gè)用戶僅能統(tǒng)計(jì)其有讀權(quán)限的記錄數(shù)云函數(shù)端:因?qū)儆诠芾矶耍虼丝梢越y(tǒng)計(jì)集合的所有記錄數(shù)。

技術(shù)文檔:Collection.count()

const db = wx.cloud.database()
const _ = db.command
db.collection("china")
  .where({             
    gdp: _.gt(3000)    
  })
  .count().then(res => {
    console.log(res.total)
  })

field、orderBy、skip、limit對count是無效的,只有where才會影響count的結(jié)果,count只會返回記錄數(shù),不會返回查詢到的數(shù)據(jù)。

新增記錄Collection.add

在前面我們將知乎日報(bào)的數(shù)據(jù)導(dǎo)入到了zhihu_daily的集合里,接下來,我們就來給zhihu_daily新增記錄。

技術(shù)文檔:Collection.add

使用開發(fā)者工具新建一個(gè)zhihudaily的頁面,然后在zhihudaily.wxml里輸入以下代碼,新建一個(gè)綁定了事件處理函數(shù)為addDaily的button按鈕:

<button bindtap="addDaily">新增日報(bào)數(shù)據(jù)</button>

然后再在zhihudaily.js里輸入以下代碼,在事件處理函數(shù)addDaily里調(diào)用Collection.add,往集合zhihu_daily里添加一條記錄,如果傳入的記錄對象沒有 _id 字段,則由后臺自動(dòng)生成 _id;若指定了 _id,則不能與已有記錄沖突。

  addDaily(){
    db.collection('zhihu_daily').add({
      data: {
        _id:"daily9718005",
        title: "元素,生生不息的宇宙諸子",
        images: [
    "https://pic4.zhimg.com/v2-3c5d866701650615f50ff4016b2f521b.jpg"
  ],
        id: 9718005,
        url: "https://daily.zhihu.com/story/9718005",
        image: "https://pic2.zhimg.com/v2-c6a33965175cf81a1b6e2d0af633490d.jpg",
        share_url: "http://daily.zhihu.com/story/9718005",
        body:"<p><strong><strong>謹(jǐn)以此文,紀(jì)念元素周期表發(fā)布 150 周年。</strong></strong></p>\r\n<p>地球,世界,和生活在這里的蕓蕓眾生從何而來,這是每個(gè)人都曾有意無意思考過的問題。</p>\r\n<p>科幻小說家道格拉斯·亞當(dāng)斯給了一個(gè)無厘頭的答案,42;宗教也給出了諸神創(chuàng)世的虛構(gòu)場景;</p>\r\n<p>最為恢弘的畫面,則是由科學(xué)給出的,另一個(gè)意義上的<strong>生死輪回,一場屬于元素的生死輪回</strong>。</p>"
      }
    })
      .then(res => {
        console.log(res)
      })
      .catch(console.error)
  }

點(diǎn)擊新增日報(bào)數(shù)據(jù)的button,會看到控制臺打印的res對象里包含新增記錄的_id為我們自己設(shè)置的daily9718005。打開云開發(fā)控制臺的數(shù)據(jù)庫標(biāo)簽,打開集合zhihu_daily,翻到最后一頁,就能看到我們新增的記錄啦。

_openid與集合權(quán)限

注意和導(dǎo)入的數(shù)據(jù)不同的是,在小程序端新增記錄,都會自動(dòng)添加一個(gè)_openid的字段,它的值等于用戶 openid,_openid的值是不允許修改的。當(dāng)我們把集合的權(quán)限改為僅創(chuàng)建者可讀寫,或所有人可讀,僅創(chuàng)建者可讀寫,在小程序端查詢或更新記錄時(shí),會自動(dòng)添加一個(gè)條件,

.where({              
   _openid:"當(dāng)前用戶的openid"    
})

所以這就是為什么盡管集合里面有數(shù)據(jù),但是由于有了這個(gè)條件,只要記錄里沒有_openid或openid不匹配就查詢不到記錄。

集合請求方法注意事項(xiàng)


get、update、count、remove、add等都是請求,在小程序端可以有callback和promise兩種寫法,但是在云函數(shù)端只能用promise,不能用callback。為了方便,建議大家統(tǒng)一使用promise的寫法,也就是then、catch。


get、update、count、remove、add請求不能在一個(gè)數(shù)據(jù)庫引用里同時(shí)存在。比如不能又是get(),又是count()的,不能這么寫:
    db.collection('china').where({
        _openid: 'xxx',
    }).get().count().add()

云函數(shù)端操作集合內(nèi)記錄

云函數(shù)端調(diào)用數(shù)據(jù)庫

在云開發(fā)能力章節(jié)我們已經(jīng)介紹過如何在云函數(shù)端調(diào)用數(shù)據(jù)庫,這里也是一樣。新建一個(gè)云函數(shù)chinadata,然后在 exports.main = async (event, context) => {}輸入以下代碼,注意是 const db = cloud.database(),wx. cloud.database(),云函數(shù)端的數(shù)據(jù)庫引用和小程序端有所不同:

const db = cloud.database()
const _ = db.command
return await db.collection("china") 
  .where({           
    gdp: _.gt(3000)    
  })
  .field({           
    _id: false, 
    city: true,
    province: true,
    gdp: true
  })
  .orderBy('gdp', 'desc') 
  .skip(0) 
  .limit(10) 
  .get()
try/catch async錯(cuò)誤處理


當(dāng)  async 函數(shù)中只要一個(gè)  await 出現(xiàn) reject 狀態(tài),則后面的  await 都不會被執(zhí)行。如果有多個(gè)  await 則可以將其都放在  try/catch 中。

然后右鍵chinadata云函數(shù)根目錄選擇在終端中打開,輸入npm install,之后上傳并部署所有文件。

?

在前面我們了解到,調(diào)用云函數(shù)可以使用本地調(diào)試、云端測試,我們還可以在小程序端調(diào)用云函數(shù),將云函數(shù)的數(shù)據(jù)返回到小程序端來。使用開發(fā)者工具在chinadata.wxml里輸入以下代碼,也就是我們通用點(diǎn)擊按鈕觸發(fā)事件處理函數(shù):

<button bindtap="callChinaData">調(diào)用chinadata云函數(shù)</button>

再在事件處理函數(shù)里調(diào)用云函數(shù),在chinadata.js里輸入getChinaData事件處理函數(shù)來調(diào)用chinadata云函數(shù):

  getChinaData() {
    wx.cloud.callFunction({
      name: 'chinadata',
      success: res => {
        console.log("云函數(shù)返回的數(shù)據(jù)",res.result.data)
      },
      fail: err => {
        console.error('云函數(shù)調(diào)用失敗:', err)
      }
    })
  },

在模擬器里點(diǎn)擊調(diào)用chinadata云函數(shù)的button按鈕,就能在控制臺里看到云函數(shù)返回的查詢到的結(jié)果,大家可以通過setData的方式將查詢的結(jié)果渲染到小程序頁面,這里就不介紹啦。

刪除多條數(shù)據(jù)記錄

基于數(shù)據(jù)庫集合的引用Collection,我們可以先匹配 where 語句查詢到相關(guān)條件的多條記錄,再來調(diào)用Collection.remove()來進(jìn)行刪除。五個(gè)查詢方法,skip和limit不支持,field、orderBy沒有意義,只有where條件可以用來篩選記錄。數(shù)據(jù)一旦刪除就不能再找回了。

技術(shù)文檔:Collection.remove()

我們可以把之前建好的chinadata云函數(shù) exports.main = async (event, context) => {}里的代碼修改為如下,即刪除省份province為廣東的所有數(shù)據(jù):

  return await db.collection('china')
    .where({
      province:"廣東"
    })
    .remove()

在模擬器里點(diǎn)擊調(diào)用chinadata云函數(shù)的button按鈕,就能在控制臺里看到云函數(shù)返回的對象,其中包含stats: {removed: 22},即刪除了22條數(shù)據(jù)。

更新多條記錄Collection.update

我們可以把之前建好的chinadata云函數(shù) exports.main = async (event, context) => {}里的代碼修改為如下,也就是先查詢省份province為湖北的記錄,給這個(gè)記錄更新一個(gè)字段英文省份名pro-en:

  return await db.collection('china')
    .where({
      province:"湖北"
    })
    .update({
      data: {
        "pro-en": "Hubei"
      },
    })

這里要注意的是,pro-en這個(gè)字段之前是沒有的,通過Collection.update不只是起到更新的作用,還可以批量新增字段并賦值,也就是update時(shí)記錄里有相同字段就更新,沒有就新增; "pro-en": "Hubei",直接使用pro-en會報(bào)錯(cuò),用雙引號效果等價(jià)。

如果你想給導(dǎo)入的數(shù)據(jù)添加_openid字段,只用云函數(shù)是沒法實(shí)現(xiàn)的,因?yàn)樵坪瘮?shù)沒有用戶的登錄態(tài)。我們需要先在小程序端調(diào)用云函數(shù)比如login返回openid,再將openid的值再傳給chinadata云函數(shù),才能給記錄添加openid。

操作單個(gè)記錄doc的字段值

在前面我們已經(jīng)了解了基于集合引用Collection構(gòu)建查詢條件的5個(gè)方法,以及一些請求方法,接下來我們來講一下基于集合記錄引用Document的四個(gè)請求方法:獲取單個(gè)記錄數(shù)據(jù)Document.get()、刪除單個(gè)記錄Document.remove()、更新單個(gè)記錄Document.update()、替換更新單個(gè)記錄Document.set()。和基于Collection不一樣的是,前者的增刪改查是可以批量多條的,而基于Document則是操作單條記錄。

查詢集合collection里的記錄常用于獲取文章、資訊、商品、產(chǎn)品等等的列表;而查詢單個(gè)記錄doc的字段值則常用于這些列表里的詳情內(nèi)容。如果你在開發(fā)中需要增刪改查某個(gè)記錄的字段值,為了方便讓程序可以根據(jù)_id找到對應(yīng)的記錄,建議在創(chuàng)建記錄的時(shí)候_id用程序有規(guī)則的生成。

查詢單個(gè)記錄doc的字段值

集合里的每條記錄都有一個(gè) _id 字段用以唯一標(biāo)志一條記錄,_id 的數(shù)據(jù)格式可以是number數(shù)字,也可以是string字符串。這個(gè)_id是可以自定義的,當(dāng)導(dǎo)入記錄或?qū)懭胗涗洓]有自定義時(shí)系統(tǒng)會自動(dòng)生成一個(gè)非常長的字符串。查詢記錄doc的字段field值就是基于_id的。

技術(shù)文檔:獲取單個(gè)記錄數(shù)據(jù)Document.get()

比如我們查詢其中知乎日報(bào)的一篇文章(也就是其中一條記錄)的數(shù)據(jù),使用開發(fā)者工具zhihudaily頁面的zhihudaily.js的onLoad生命周期函數(shù)里輸入以下代碼(db不要重復(fù)聲明):

db.collection('zhihu_daily').doc("daily9718006")
  .get()
  .then(res => {
  console.log('單個(gè)記錄的值',res.data)
  })
  .catch(err => {
    console.error(err)
  })
},

如果集合的數(shù)據(jù)是導(dǎo)入的,那_id是自動(dòng)生成的,自動(dòng)生成的_id是字符串string,所以doc內(nèi)使用了單引號(雙引號也是可以的哦),如果你自定義的_id是number類型,比如自定義的_id為20191125,查詢時(shí)為doc(20191125)即可,這只是基礎(chǔ)知識啦。

刪除單條記錄

技術(shù)文檔:刪除單個(gè)記錄Document.remove()

  removeDaily(){
    db.collection('zhihu_daily').doc("daily9718006")
      .remove()
      .then(console.log)
      .catch(console.error)
  }

更新單條記錄

技術(shù)文檔:更新單個(gè)記錄Document.update()

  updateDaily(){
    db.collection('zhihu_daily').doc("daily9718006")
      .update({
        data:{
          title: "【知乎日報(bào)】元素,生生不息的宇宙諸子",
        }
      })
  },

替換更新記錄

技術(shù)文檔:替換更新單個(gè)記錄Document.set()

  setDaily(){
    db.collection('zhihu_daily').doc("daily9718006")
      .set({
        data: {
          "title": "為什么狗會如此親近人類?",
          "images": [
            "https://pic4.zhimg.com/v2-4cab2fbf4fe9d487910a6f2c54ab3ed3.jpg"
          ],
          "id": 9717547,
          "url": "https://daily.zhihu.com/story/9717547",
          "image": "https://pic4.zhimg.com/v2-60f220ee6c5bf035d0eaf2dd4736342b.jpg",
          "share_url": "http://daily.zhihu.com/story/9717547",
          "body":  "<p>讓狗從兇猛的野獸變成忠實(shí)的愛寵,涉及了宏觀與微觀上的兩層故事:我們?nèi)绾卧诤暧^上馴養(yǎng)了它們,以及這些馴養(yǎng)在生理層面究竟意味著什么。</p>\r\n<p><img class=\"content-image\" src=\"http://pic1.zhimg.com/70/v2-4147c4b02bf97e95d8a9f00727d4c184_b.jpg\" alt=\"\"></p>\r\n<p>狗是灰狼(Canis lupus)被人類馴養(yǎng)后形成的亞種,至少可以追溯到 1 萬多年以前,是人類成功馴化的第一種動(dòng)物。在這漫長的歲月里,人類的定向選擇強(qiáng)烈改變了這個(gè)馴化亞種的基因頻率,使它呈現(xiàn)出極高的多樣性,尤其體現(xiàn)在生理形態(tài)上。</p>"
        }
      })
  }
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號