Опрос MongoDB (через pymongo) в случае нечувствительности к регистру - PullRequest
19 голосов
/ 07 июня 2011

В настоящее время я создаю веб-сайт на языке python (пирамида), который требует, чтобы пользователи регистрировались и входили в систему. Система позволяет пользователям выбирать имя пользователя, которое может состоять из заглавных букв, строчных букв и цифр.

Проблема возникает, когда два пользователя случайно не используют одно и то же имя пользователя, т. Е. В моей системе «randomUser» должен совпадать с «RandomUser» или «randomuser».

К сожалению (в данном случае), поскольку Mongo хранит строки как чувствительные к регистру, потенциально может быть несколько пользователей с одинаковым именем пользователя.

Мне известен метод запроса монго для строк без учета регистра:

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

Однако, похоже, это не работает в моем методе запроса с использованием pymongo:

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

Это правильный способ структурирования запроса для pymongo (я предполагаю, что нет)?

Этот запрос будет использоваться всякий раз, когда учетная запись пользователя создается или входит в нее (так как он должен проверить, существует ли имя пользователя в системе). Я знаю, что это не самый эффективный запрос, поэтому должен ли он иметь значение, если он используется только при входе в систему или создании учетной записи? Желательно вместо этого делать что-то вроде принуждения пользователей выбирать только имена пользователей в нижнем регистре (полностью исключая необходимость запросов без учета регистра)?

Ответы [ 2 ]

38 голосов
/ 07 июня 2011

PyMongo использует собственные регулярные выражения python, так же как оболочка mongo использует собственные регулярные выражения javascript. Чтобы написать эквивалентный запрос того, что вы написали в оболочке выше, вы должны использовать:

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

Обратите внимание, что это позволит избежать использования любого индекса, который может существовать в поле name. Обычным шаблоном для поиска или сортировки без учета регистра является наличие в вашем документе второго поля, например, name_lower, которое всегда устанавливается каждый раз при изменении name (в данном случае это версия name в нижнем регистре). ). Затем вы бы запросили такой документ, как:

db.stuff.find_one({'name_lower': username.lower()})
0 голосов
/ 21 марта 2019

Принятый ответ опасен, он будет соответствовать любой строке, содержащей имя пользователя! Безопасный вариант - соответствовать точной строке:

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