uniCloud JQL語法(一)

JQL概述

JQL,全稱 javascript query language榨呆,是一種js方式操作數(shù)據(jù)庫的規(guī)范。

使用場景
客戶端clientDB,包括js內(nèi)以及unicloud-db組件內(nèi)
HBuilderX JQL數(shù)據(jù)庫管理器
啟用了jql擴(kuò)展的云函數(shù)

不同場景的區(qū)別

  • JQL數(shù)據(jù)庫管理器:
    ○ 不會校驗(yàn)任何權(quán)限暖夭,相當(dāng)于以數(shù)據(jù)庫管理員的身份執(zhí)行
    ○ 即使是admin不能讀寫的password類型數(shù)據(jù)也可以讀寫
    ○ 不會觸發(fā)數(shù)據(jù)庫觸發(fā)器
    ○ 不可以執(zhí)行action云函數(shù)
  • 客戶端clientDB:
    ○ 完整的權(quán)限校驗(yàn),執(zhí)行操作的用戶不可以操作自己權(quán)限之外的數(shù)據(jù)
    ○ admin用戶不可操作password類型的數(shù)據(jù)
  • 云函數(shù)JQL:
    ○ 同clientDB撵孤,但是password類型的數(shù)據(jù)可以配置權(quán)限迈着,默認(rèn)權(quán)限是false,可以被admin用戶操作邪码。
    ○ 可以通過setUser指定當(dāng)前執(zhí)行數(shù)據(jù)庫操作的用戶身份裕菠。

JQL包含的模塊

image.png

JQL的限制
○ 會對數(shù)據(jù)庫操作進(jìn)行序列化,除Date類型闭专、RegExp之外的所有不可JSON序列化的參數(shù)類型均不支持(例如:undefined)
○ 為了嚴(yán)格控制權(quán)限奴潘,禁止使用set方法
○ 為了數(shù)據(jù)校驗(yàn)?zāi)車?yán)格限制,更新數(shù)據(jù)庫時不可使用更新操作符db.command.inc等
○ 更新數(shù)據(jù)時鍵值不可使用{'a.b.c': 1}的形式影钉,需要寫成{a:{b:{c:1}}}形式

客戶端調(diào)用

const db = uniCloud.database()

// 使用`jql`查詢list表內(nèi)`name`字段值為`hello-uni-app`的記錄
db.collection('list')
  .where('name == "hello-uni-app"')
  .get()
  .then((res)=>{
    // res 為數(shù)據(jù)庫查詢結(jié)果
  }).catch((err)=>{
    // err.message 錯誤信息
    // err.code 錯誤碼
  })

JQL方法使用限制

下面這些方法必須嚴(yán)格按照下面的順序進(jìn)行調(diào)用画髓,其他方法需要在這些方法之后調(diào)用(不限制順序)
單表查詢collection aggregate geoNear doc where field groupBy groupField
聯(lián)表查詢
臨時表:collection geoNear where field orderBy skip limit getTemp
虛擬聯(lián)表:collection foreignKey where field groupBy groupField distinct orderBy skip limit get

新增數(shù)據(jù)記錄

方法:collection.add(data) 其中data類型object|array
data中不需要包括_id字段,數(shù)據(jù)庫會自動維護(hù)該字段平委。

const db = uniCloud.database();
const collection = db.collection('user');
//單條記錄
db.collection('user').add({name:"王五"})
//多條記錄
let res = await collection.add([{
  name: '張三'
},{
  name: '李四'
},{
  name: '王五'
}])

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

通過指定文檔id刪除:collection.doc(_id).remove()
比如:

const db = uniCloud.database();
await db.collection("table1").doc("5f79fdb337d16d0001899566").remove()

條件查詢刪除
collection.where().remove()

// 刪除字段a的值大于2的文檔
try {
    await db.collection("table1").where("a>2").remove()
} catch (e) {
    uni.showModal({
        title: '提示',
        content: e.message
    })
}

刪除所有的數(shù)據(jù)

const dbCmd = db.command
const db = uniCloud.database();
await db.collection("table1").where({
  _id: dbCmd.neq(null)
}).remove()

更新數(shù)據(jù)記錄

通過指定文檔id更新:collection.doc(_id).update(Object data)
條件查詢更新

const db = uniCloud.database();
let collection = db.collection("table1")
let res = await collection.where({_id:'doc-id'})
  .update({
    name: "Hey",
    count: {
      fav: 1
    }
  });

內(nèi)置云端環(huán)境變量

image.png

在字符串內(nèi)使用
db.collection('user').where('_id==$cloudEnv_uid').get()
在對象內(nèi)使用
db.collection('user').where({ _id: db.getCloudEnv('$cloudEnv_uid') }).get()
使用正則查詢
const res = await db.collection('goods').where(`${new RegExp(searchVal, 'i')}.test(name)`).get()

聯(lián)表查詢

臨時表:getTemp方法返回的結(jié)果奈虾,例:const article = db.collection('article').getTemp(),此處 article 就是一個臨時表
虛擬聯(lián)表:主表與副表聯(lián)表產(chǎn)生的表,例:db.collection(article, 'comment').get()

JQL聯(lián)表查詢有以下兩種寫法:

// 直接關(guān)聯(lián)多個表為虛擬聯(lián)表再進(jìn)行查詢肉微,舊寫法匾鸥,目前更推薦使用getTemp進(jìn)行聯(lián)表查詢
const res = await db.collection('order,book').where('_id=="1"').get()// 直接關(guān)聯(lián)order和book之后再過濾

// 使用getTemp先過濾處理獲取臨時表再聯(lián)表查詢,推薦用法
const order = db.collection('order').where('_id=="1"').getTemp() // 注意結(jié)尾的方法是getTemp碉纳,對order表過濾得到臨時表
const res = await db.collection(order, 'book').get() // 將獲取的order表的臨時表和book表進(jìn)行聯(lián)表查詢

表關(guān)聯(lián)示例:定義order表和book表 schema

// order表schema
{
  "bsonType": "object",
  "required": [],
  "permission": {
    "read": true
  },
  "properties": {
    "book_id": {
      "bsonType": "string",
      "foreignKey": "book._id" // 使用foreignKey表示勿负,此字段關(guān)聯(lián)book表的_id。
    },
    "quantity": {
      "bsonType": "int"
    }
  }
}

// book表schema
{
  "bsonType": "object",
  "required": [],
  "permission": {
    "read": true
  },
  "properties": {
    "title": {
      "bsonType": "string"
    },
    "author": {
      "bsonType": "string"
    }
  }
}

定義json數(shù)據(jù)

//book表
{
  "_id": "1",
  "title": "西游記",
  "author": "吳承恩"
}
{
  "_id": "2",
  "title": "水滸傳",
  "author": "施耐庵"
}
{
  "_id": "3",
  "title": "三國演義",
  "author": "羅貫中"
}
{
  "_id": "4",
  "title": "紅樓夢",
  "author": "曹雪芹"
}

//order表
{
  "book_id": "1",
  "quantity": 111
}
{
  "book_id": "2",
  "quantity": 222
}
{
  "book_id": "3",
  "quantity": 333
}
{
  "book_id": "4",
  "quantity": 444
}
{
  "book_id": "3",
  "quantity": 555
}
// 客戶端聯(lián)表查詢
const db = uniCloud.database()
const order = db.collection('order').field('book_id,quantity').getTemp() // 臨時表field方法內(nèi)需要包含關(guān)聯(lián)字段劳曹,否則無法建立關(guān)聯(lián)關(guān)系
const book = db.collection('book').field('_id,title,author').getTemp() // 臨時表field方法內(nèi)需要包含關(guān)聯(lián)字段笆环,否則無法建立關(guān)聯(lián)關(guān)系

db.collection(order, book) // 注意collection方法內(nèi)需要傳入所有用到的表名,用逗號分隔厚者,主表需要放在第一位
  .where('book_id.title == "三國演義"') // 查詢order表內(nèi)書名為“三國演義”的訂單
  .get()
  .then(res => {
    console.log(res);
  }).catch(err => {
    console.error(err)
  })

查詢結(jié)果如下:

{
    "code": "",
    "message": "",
    "data": [{
        "_id": "b8df3bd65f8f0d06018fdc250a5688bb",
        "book_id": [{
            "_id": "3",
            "author": "羅貫中",
            "title": "三國演義"
        }],
        "quantity": 555
    }, {
        "_id": "b8df3bd65f8f0d06018fdc2315af05ec",
        "book_id": [{
            "_id": "3",
            "author": "羅貫中",
            "title": "三國演義"
        }],
        "quantity": 333
    }]
}

存在外鍵時結(jié)果返回的區(qū)別

主表某字段foreignKey指向副表時躁劣,返回結(jié)果格式為:

{
"主表字段名1": "xxx",
"主表字段名2": "xxx",
"主表內(nèi)foreignKey指向副表的字段名": [{
  "副表字段名1": "xxx",
  "副表字段名2": "xxx",
}]
}

當(dāng)副表某字段foreignKey指向主表時,其返回結(jié)果格式為:

{
  "主表字段名1": "xxx",
  "主表字段名2": "xxx",
  "主表內(nèi)被副表foreignKey指向的字段名": { 
    "副表1表名": [{ // 一個主表字段可能對應(yīng)多個副表字段的foreignKey
      "副表1字段名1": "xxx",
      "副表1字段名2": "xxx",
    }],
    "副表2表名": [{ // 一個主表字段可能對應(yīng)多個副表字段的foreignKey
      "副表2字段名1": "xxx",
      "副表2字段名2": "xxx",
    }],
    "_value": "主表字段原始值" // 使用副表foreignKey查詢時會在關(guān)聯(lián)的主表字段內(nèi)以_value存儲該字段的原始值库菲,新增于HBuilderX 3.1.16
  }
}

可簡單理解為:
主表foreignKey指向副表時账忘,查詢結(jié)果:關(guān)聯(lián)字段只包含副表查詢結(jié)果,不含表名
副表foreignKey指向主表時熙宇,查詢結(jié)果:關(guān)聯(lián)字段中會包含副表的表名和查詢結(jié)果

臨時聯(lián)表查詢
使用臨時表進(jìn)行聯(lián)表查詢鳖擒,可以先對主表或者副表進(jìn)行過濾,然后在處理后的臨時表的基礎(chǔ)上生成虛擬聯(lián)表烫止。

// 先過濾article表蒋荚,再獲取虛擬聯(lián)表聯(lián)表獲取評論
const article = db.collection('article').where('article_id=="1"').getTemp() // 注意是getTemp不是get
const res = await db.collection(article, 'comment').get()

設(shè)置表字段別名
語法:原字段名 as 新字段名

const db = uniCloud.database()
const order = db.collection('order').field('book_id,quantity').getTemp()
const book = db.collection('book').field('_id,title as book_title,author as book_author').getTemp()

db.collection(order, book)
  .where('book_id.book_title == "三國演義"') // 如果field內(nèi)對副表字段title進(jìn)行了重命名,where方法內(nèi)則需要使用重命名之后的字段名
  .get()
  .then(res => {
    console.log(res);
  }).catch(err => {
    console.error(err)
  })

查詢結(jié)果如下

{
    "code": "",
    "message": "",
    "data": [{
        "_id": "b8df3bd65f8f0d06018fdc250a5688bb",
        "book_id": [{
            "book_author": "羅貫中",
            "book_title": "三國演義"
        }],
        "order_quantity": 555
    }, {
        "_id": "b8df3bd65f8f0d06018fdc2315af05ec",
        "book_id": [{
            "book_author": "羅貫中",
            "book_title": "三國演義"
        }],
        "order_quantity": 333
    }]
}

where 簡單查詢

image.png

這里的test方法比較強(qiáng)大馆蠕,格式為:正則規(guī)則.test(fieldname)期升。
具體到這個正則 /abc/.test(content),類似于sql中的content like '%abc%'互躬,即查詢所有字段content包含abc的數(shù)據(jù)記錄播赁。
注意
? 不支持非操作
? 編寫查詢條件時,除test外吼渡,均為運(yùn)算符左側(cè)為數(shù)據(jù)庫字段容为,右側(cè)為常量
簡單查詢條件內(nèi)要求二元運(yùn)算符兩側(cè)不可均為數(shù)據(jù)庫內(nèi)的字段
上述寫法的查詢語句可以在權(quán)限校驗(yàn)階段與schema內(nèi)配置的permission進(jìn)行一次對比校驗(yàn),如果校驗(yàn)通過則不會再查庫進(jìn)行權(quán)限校驗(yàn)寺酪。

復(fù)雜查詢條件
復(fù)雜查詢內(nèi)可以使用數(shù)據(jù)庫運(yùn)算方法
示例:數(shù)據(jù)表test內(nèi)有以下數(shù)據(jù)

{
  "_id": "1",
  "name": "n1",
  "chinese": 60, // 語文
  "math": 60 // 數(shù)學(xué)
}
{
  "_id": "2",
  "name": "n2",
  "chinese": 60,
  "math": 70
}
{
  "_id": "3",
  "name": "n3",
  "chinese": 100,
  "math": 90
}
//篩選語文數(shù)學(xué)總分大于150的數(shù)據(jù)
const db = uniCloud.database()
const res = await db.collection('test')
.where('add(chinese,math) > 150')
.get()

注意:復(fù)雜查詢條件不可以使用正則查詢

查詢列表分頁
可以通過skip+limit來進(jìn)行分頁查詢

const db = uniCloud.database()
db.collection('book')
  .where('status == "onsale"')
  .skip(20) // 跳過前20條
  .limit(20) // 獲取20條
  .get()
  
// 上述用法對應(yīng)的分頁條件為:每頁20條取第2頁

字段過濾field

// 聯(lián)表查詢
db.collection('order,book') // 注意collection方法內(nèi)需要傳入所有用到的表名坎背,用逗號分隔,主表需要放在第一位
  .field('book_id{title,author},quantity') // 這里聯(lián)表查詢book表返回book表內(nèi)的title寄雀、book表內(nèi)的author得滤、order表內(nèi)的quantity
  .get()
//或者
db.collection('order,book')
  .where('book_id.title == "三國演義"')
  .field('book_id.title,book_id.author,quantity as order_quantity') // book_id.title、book_id.author為副表字段咙俩,使用別名時效果和上一個示例不同耿戚,請見下方說明
  .orderBy('order_quantity desc') // 按照order_quantity降序排列
  .get()

字段別名的話,還是用as 別名阿趁,和之前用法一致
比如

db.collection('order,book')
  .where('book_id.title == "三國演義"')
  .field('book_id{title as book_title,author as book_author},quantity as order_quantity')
 // 這里聯(lián)表查詢book表返回book表內(nèi)的title膜蛔、book表內(nèi)的author、order表內(nèi)的quantity脖阵,
 //并將title重命名為book_title皂股,author重命名為book_author,quantity重命名為order_quantity
  .orderBy('order_quantity desc') // 按照order_quantity降序排列

排序orderBy
orderBy允許進(jìn)行多個字段排序命黔,以逗號分隔呜呐。每個字段可以指定 asc(升序)、desc(降序)悍募。默認(rèn)是升序蘑辑。
寫在前面的排序字段優(yōu)先級高于后面。
orderBy('quantity asc, create_date desc') //按照quantity字段升序排序坠宴,quantity相同時按照create_date降序排序

限制查詢記錄的條數(shù)limit
使用limit方法洋魂,可以查詢有限條數(shù)的數(shù)據(jù)記錄。
limit默認(rèn)值是100喜鼓,即不設(shè)置的情況下副砍,默認(rèn)返回100條數(shù)據(jù)。
limit有最大值庄岖,騰訊云限制為最大1000條豁翎,阿里云限制為最大500條。

// 這以上面的book表數(shù)據(jù)為例隅忿,查價格最高的一本書
  db.collection('book')
    .orderBy('price desc')
    .limit(1)
    .get()

只查一條記錄getone

// 這以上面的book表數(shù)據(jù)為例
const db = uniCloud.database()
  db.collection('book')
    .where({
      title: '西游記'
    })
    .get({
      getOne:true
    })
    .then(res => {
      console.log(res);
    }).catch(err => {
      console.error(err)
    })

如果使用uniCloud-db組件心剥,則在組件的屬性上增加一個 getone

統(tǒng)計(jì)數(shù)量getcount
affectedDocs表示從服務(wù)器返回給前端的數(shù)據(jù)條數(shù)。默認(rèn)100條背桐,可通過limit方法調(diào)整刘陶。
count則是指符合查詢條件的記錄總數(shù),至于這些記錄是否返回給前端牢撼,和count無關(guān)匙隔。

count計(jì)數(shù)又有2種場景:
單純統(tǒng)計(jì)數(shù)量,不返回數(shù)據(jù)明細(xì)
使用count()方法熏版,如db.collection('order').count()
可以繼續(xù)加where等條件進(jìn)行數(shù)據(jù)記錄過濾纷责。

查詢記錄返回詳情,同時返回符合查詢條件的數(shù)量撼短、使用getCount參數(shù)

// 這以上面的order表數(shù)據(jù)為例
const db = uniCloud.database()
  db.collection('order')
    .get({
      getCount:true
    })
    .then(res => {
      console.log(res);
    }).catch(err => {
      console.error(err)
    })

如果使用uniCloud-db組件再膳,則在組件的屬性上增加一個 getcount

數(shù)據(jù)去重distinct
通過.distinct()方法,對數(shù)據(jù)查詢結(jié)果中重復(fù)的記錄進(jìn)行去重曲横。

const res = await db.collection('score')
.field('grade,class')
.distinct() // 注意distinct方法沒有參數(shù)
.get()

查詢返回結(jié)果
{data:[{grade:"1",class:"A"},{grade:"1",class:"B"},{grade:"2",class:"A"}]}
注意:distinct指對返回結(jié)果中完全相同的記錄進(jìn)行去重喂柒,重復(fù)的記錄只保留一條不瓶。因?yàn)開id字段是必然不同的,所以使用distinct時必須同時指定field灾杰,且field中不可存在_id字段蚊丐。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市艳吠,隨后出現(xiàn)的幾起案子麦备,更是在濱河造成了極大的恐慌,老刑警劉巖昭娩,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凛篙,死亡現(xiàn)場離奇詭異,居然都是意外死亡栏渺,警方通過查閱死者的電腦和手機(jī)呛梆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來磕诊,“玉大人削彬,你說我怎么就攤上這事⌒阒伲” “怎么了融痛?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長神僵。 經(jīng)常有香客問我雁刷,道長,這世上最難降的妖魔是什么保礼? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任沛励,我火速辦了婚禮,結(jié)果婚禮上炮障,老公的妹妹穿的比我還像新娘目派。我一直安慰自己,他們只是感情好胁赢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布企蹭。 她就那樣靜靜地躺著,像睡著了一般智末。 火紅的嫁衣襯著肌膚如雪谅摄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天系馆,我揣著相機(jī)與錄音送漠,去河邊找鬼。 笑死由蘑,一個胖子當(dāng)著我的面吹牛闽寡,可吹牛的內(nèi)容都是我干的代兵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼爷狈,長吁一口氣:“原來是場噩夢啊……” “哼植影!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起淆院,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤何乎,失蹤者是張志新(化名)和其女友劉穎句惯,沒想到半個月后土辩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡抢野,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年拷淘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片指孤。...
    茶點(diǎn)故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡启涯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出恃轩,到底是詐尸還是另有隱情结洼,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布叉跛,位于F島的核電站松忍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏筷厘。R本人自食惡果不足惜鸣峭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酥艳。 院中可真熱鬧摊溶,春花似錦、人聲如沸充石。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骤铃。三九已至浓镜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間劲厌,已是汗流浹背膛薛。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留补鼻,地道東北人哄啄。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓雅任,卻偏偏與公主長得像,于是被迫代替她去往敵國和親咨跌。 傳聞我的和親對象是個殘疾皇子沪么,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容