2014-04-12 14 views
6

我正在實施一種方法讓用戶在我正在編寫的Meteor應用程序中更改他們的用戶名。在接受更改之前,我想檢查用戶名是否已經存在。用戶名可以包含大寫和小寫,但不管大小寫,它們都必須是唯一的名稱。例如,bobBob不能同時存在。流星:如何做一個不區分大小寫的collection.findOne()?

問題是,我似乎無法弄清楚如何做一個不區分大小寫的collection.findOne()。例如,假設我有一個名爲檔案的收集,我希望能夠做這樣的事情:

newName = "bob"; 

//Assume "Bob" exists as a username in the Profiles collection; 

var isAlreadyRegistered = Profiles.findOne({"username": newName}); 

if (isAlreadyRegistered == null) { 
    saveUsername(); 
}; 

回答

12

你可以使用regular expression.

var isAlreadyRegistered = Profiles.findOne({"username": /^newName$/i }); 

,也可以查詢這樣也:

var isAlreadyRegistered = Profiles.findOne({ "username" : { 
        $regex : new RegExp(newName, "i") } } 
       ); 
+1

很好的答案,但我不知道爲什麼你的第一個例子不適合我,而第二個例子。 – adrianmc

2

有兩種方法,而且你可以在最適合你的方式上有所不同,但兩者是相當可怕的,因爲實際上做的MongoDB案「敏感」匹配:

第一種方法是使用$regex

Profiles.findOne({ "username": { 
    "$regex": "^" + newName + "\\b", "$options": "i" 
}}) 

這詞,只有確切的詞從一個不區分大小寫的方式字符串的開頭相匹配。這裏的問題是你正在掃描一個索引。

第二種方法是使用項目總:

db.collection("profiles").aggregate([ 
    { "$project": { 
     "username": 1, 
     "lower": { "$toLower": "$username" } 
    }}, 
    { "$match": { 
     "username": newName 
    }} 
]) 

而你做到這一點,其中當然newName已經轉換爲小寫。

這裏的問題是,將$project在管道中的一切。但是,如果您首先可以使用$match,那麼它可能很有用。

當然我認爲aggregate只在服務器端,而不是通過Minimongo,所以有這樣的考慮。

+0

我相信我確實這樣說過,並且表示可以在你自己的方法裏面的服務器上使用它。 –

+0

@AndrewMao爲了所有讀者和你自己的利益,那個陳述是錯誤的。所有的框架實現在某些時候使用並允許訪問底層驅動程序及其方法,所以通過抓取本地集合對象,您應該始終能夠獲得此方法,而且大多數框架確實至少提供了一個「runCommand」接口,在某種形式下它也可以這樣完成。所有驅動程序中的MongoDB方法實際上都是以這種方式實現的。所以不管調用語法如何,你都不應該說它不可用。 –

1

作爲您的基礎用例的解決方案,我建議使用兩個字段來存儲用戶名,而不是一個。

內置用戶名字段應存儲用戶名的小寫版本。另一方面,額外的領域存儲了原始的大小寫敏感版本。

搜索將針對'username'字段進行搜索標準的小寫以及使用之前。

+0

在什麼**應該**完成的大前提下。你是非常正確的,因爲需要一個實際上在文檔中具有小寫值並且被索引的字段。但其他選擇僅僅表明,實際上**有**的方式來做到這一點,甚至是「飛行中」,這經常被忽視。 –

+1

是的,其中一個有趣的案例,其中的問題是問一些具體的問題,但其中有很好的答案,但實際的最佳實踐來解決根本問題並沒有被問到。 – alanning