在不区分大小写的情况下有效地查询MongoDB(通过pymongo)

问题描述 投票:19回答:2

我目前正在创建一个python(金字塔)网站,要求用户注册并登录。系统允许用户选择一个用户名,可以是大写字母,小写字母和数字的混合。

当确保两个用户不小心共享相同的用户名时会出现问题,即在我的系统中,'randomUser'应该与'RandomUser'或'randomuser'相同。

不幸的是(在这种情况下)因为Mongo将字符串存储为区分大小写,因此可能会有许多用户使用“相同”的用户名。

我知道查询mongo的不区分大小写的字符串的方法:

db.stuff.find_one({"foo": /bar/i});

但是,这在使用pymongo的查询方法中似乎不起作用:

username = '/' + str(username) + '/i'
response = request.db['user'].find_one({"username":username},{"username":1})

这是构造pymongo查询的正确方法(我假设没有)?

无论何时创建或登录用户帐户,都将使用此查询(因为它必须检查系统中是否存在用户名)。我知道这不是最有效的查询,所以它是否仅用于登录或帐户创建是否重要?是否更愿意做一些事情,比如强迫用户只选择小写的用户名(完全不需要不区分大小写的查询)?

python mongodb case-insensitive pymongo
2个回答
40
投票

PyMongo使用本机python正则表达式,就像mongo shell使用本机javascript正则表达式一样。要编写您在上面的shell中编写的内容的等效查询,您将使用:

db.stuff.find_one({'name': re.compile(username, re.IGNORECASE)})

请注意,这将避免使用name字段中可能存在的任何索引。不区分大小写的搜索或排序的常见模式是在文档中包含第二个字段,例如name_lower,每当name发生更改时总是设置(在本例中为name的较低版本)。然后,您将查询如下文档:

db.stuff.find_one({'name_lower': username.lower()})

1
投票

接受的答案很危险,它将匹配包含用户名的任何字符串!安全选项是匹配确切的字符串:

import re
db.stuff.find_one({'name': re.compile('^' + username + '$', re.IGNORECASE)})

更安全,逃避可能影响正则表达式匹配的任何特殊字符的变量:

import re
db.stuff.find_one({'name': re.compile('^' + re.escape(username) + '$', re.IGNORECASE)}) 
© www.soinside.com 2019 - 2024. All rights reserved.