Ruby on Rails:model scopes搭配sql語法實現多關鍵字查詢

icelandcheng
5 min readNov 4, 2019

--

現在多數的網站,基本上都會建置搜尋的功能,以供給使用者更友善的操作介面,尤其像後台管理系統網站,為了提供管理者可以快速找出要查看的會員資訊,會員搜尋功能幾乎已經是基本配備,而且考量使用者操作的友善度,搜尋功能有時已經不能只是依輸入字串去找出完全相符的資料了,甚至需找出所有包含輸入字串的相關資料呈現給使用者,或者須提供使用者輸入多個字串去找出相關的資料,例如搜尋會員時,管理者可能會需要輸入多個關鍵字,去找出帳號包含這些關鍵字的會員,進一步的去查看這些會員的基本資訊,以下就依上述提到的多關鍵字搜尋會員這個案例,來說明可以如何實作。

運用sql語法查詢

首先,如果已經有一個User 的model,而且model有一個account欄位來紀錄每個user的帳號資訊,我們可以直接用下面的query來找出特定的帳號

User.where(account: 'admin')

但是這樣我們只能找出帳號完全符合 admin 這個字串的會員資料,所以這個時候可以搭配使用到sql的語法LIKE來找到所有帳號包含 admin 的會員資料

User.where('users.account LIKE ?', '%admin%')

除了LIKE,也可以使用RLIKE達到一樣的效果

User.where('users.account RLIKE ?', 'admin')

不過要注意就是,使用LIKE,搜尋的關鍵字串前後要加上%,才會表示前後可以有多個字符,而RLIKE是正規表達式,搜尋的關鍵字串就不用在前後特別加%。

若想搜尋帳號符合多個關鍵字,例如同時找出帳號包含 admin 或包含 test的會員,可以這樣使用LIKE語法,達到想要的結果

User.where('users.account LIKE ? OR users.account LIKE ?','%admin%',              '%test%')

使用RLIKE的話,語法則會像下面這樣

User.where('users.account RLIKE ?', 'admin|test')

比較上面這兩種方式,其實就可以看出,RLIKE將LIKE查詢多關鍵字的語法簡化的不少,所以採用RLIKE來實現多關鍵字查詢時,查詢語法是比較簡潔的,可以優先考慮使用。

包成model的scope方便使用

上面已經討論了如何搭配sql語法搜尋帳號,這些查詢的語法,可以包成User model的scope來方便呼叫,這樣如果一個網站有好幾個地方要下搜尋帳號的語法時,就不用每次都寫一大串程式出來,只要呼叫User的scope即可,例如只要在User model加入以下程式碼

scope :find_account, ->(accounts) {
sql = 'users.account RLIKE ?'
where(sql, accounts)
}

就可以直接像這樣查詢帳號

User.find_account('admin|test')

這樣查詢的程式碼很簡潔也很方便,但是缺點就是傳入的字串是要長得像 ’admin|test’ 這種形式才行,但是使用者在搜尋框輸入關鍵字的時候,可不知道要讓多個關鍵字打成這樣才行,一般人可能就用逗號分隔關鍵字( admin, test ),或是逗號後面再加個空格( admin, test ),所以find_account這個scope可以再加一些東西處理傳入的字串,像下面這樣

scope :find_account, ->(accounts) {
accounts.delete!(' ')
accounts.gsub!(',', '|') || account
sql = 'users.account RLIKE ?'
where(sql, accounts)
}

這樣查詢帳號的時候,就可像這樣使用find_account了

User.find_account('admin, test')

使用者可以直覺得用逗號分隔要查詢的關鍵字

如果光是查詢使用者帳號有包含這些關鍵字的會員已經無法滿足需求,還要再加上一併查詢使用者姓名也包含這些關鍵字的會員,這時就可以很輕鬆的在find_account這個scope再加上一些條件

scope :find_account, ->(accounts) {
accounts.delete!(' ')
accounts.gsub!(',', '|') || accounts
sql = 'users.account RLIKE ? OR '\
'users.name RLIKE ?'
where(sql, accounts, accounts)
}

這樣查詢結果就會包含搜尋會員姓名所得到的結果了

以上使用sql語法並包成model scope的方式,再搭配html表單及controller操作scope,就可以做出很不錯的多關鍵字查詢功能,像下面這樣

並且可以依據需求,在scope中任意擴充要查詢的欄位及查詢方式,或是針對傳入的參數做更多的格式檢查,做出來的功能簡單又實用。

參考資料

LIKE and RLIKE Operators

ActiveRecord Query Interface — 資料表操作

--

--

icelandcheng
icelandcheng

Written by icelandcheng

Programming Skill learner and Sharer | Ruby on Rails | Golang | Vue.js | Web Map API

No responses yet