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

vjhs03f7  于 2023-03-17  发布在  Go
关注(0)|答案(3)|浏览(128)

我目前正在用python(pyramid)创建一个网站,它需要用户注册并登录,系统允许用户选择一个用户名,用户名可以是大写字母、小写字母和数字的混合体。
当确保两个用户不会意外地共享同一个用户名时,问题就出现了,也就是说,在我的系统中,“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查询的正确方法吗(我假设不是)?
这个查询将在创建或登录用户帐户时使用(因为它必须检查用户名是否存在于系统中)。我知道这不是最有效的查询,所以如果只在登录或创建帐户时使用它,应该有关系吗?是否更可取的做法是强制用户只选择小写用户名(完全不需要不区分大小写的查询)?

vatpfxk5

vatpfxk51#

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()})
shyt4zoc

shyt4zoc2#

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

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)})
pbgvytdp

pbgvytdp3#

区分大小写

db.stuff.find_one({'name': {'$regex': f'^{username}$'}})

不区分大小写

db.stuff.find_one({'name': {'$regex': f'^{username}$', "$options": '-i'}})

相关问题