Làm cách nào để thực hiện các truy vấn không phân biệt chữ hoa chữ thường trên Mongodb?


93
var thename = 'Andrew';
db.collection.find({'name':thename});

Làm cách nào để truy vấn phân biệt chữ hoa chữ thường? Tôi muốn tìm kết quả ngay cả khi "andrew";



Một lưu ý cho tất cả những ai sẽ cố gắng sử dụng câu trả lời liên quan đến regexes: Regexes cần được làm sạch.
sean

Câu trả lời:


126

Giải pháp của Chris Fulstow sẽ hoạt động (+1), tuy nhiên, nó có thể không hiệu quả, đặc biệt nếu bộ sưu tập của bạn rất lớn. Các biểu thức chính quy không có gốc (những biểu thức không bắt đầu bằng ^, neo biểu thức chính quy vào đầu chuỗi) và những biểu thức sử dụng icờ phân biệt chữ hoa chữ thường sẽ không sử dụng chỉ mục, ngay cả khi chúng tồn tại.

Một tùy chọn thay thế mà bạn có thể xem xét là không chuẩn hóa dữ liệu của bạn để lưu trữ phiên bản viết thường của nametrường, chẳng hạn như name_lower. Sau đó, bạn có thể truy vấn một cách hiệu quả (đặc biệt nếu nó được lập chỉ mục) cho các đối sánh chính xác không phân biệt chữ hoa chữ thường như:

db.collection.find({"name_lower": thename.toLowerCase()})

Hoặc với một so khớp tiền tố (một biểu thức chính quy gốc) như:

db.collection.find( {"name_lower":
    { $regex: new RegExp("^" + thename.toLowerCase(), "i") } }
);

Cả hai truy vấn này sẽ sử dụng một chỉ mục trên name_lower.


1
Câu trả lời tuyệt vời, phương pháp tiếp cận regex của tôi thực sự chậm lại khi nó phải quét vài triệu tài liệu.
Chris Fulstow

34
Điều này thực sự không hoàn toàn chính xác, bởi vì bạn có thể tìm thấy "Andrew something" trong khi tìm kiếm "Andrew". Vì vậy, hãy điều chỉnh regex thành: new RegExp('^'+ username + '$', "i")để khớp chính xác.
Tarion

9
Theo trang web MongoDB, bất kỳ regex không phân biệt chữ hoa chữ thường nào không được lập chỉ mục hiệu quả "$ regex chỉ có thể sử dụng chỉ mục một cách hiệu quả khi biểu thức chính quy có ký tự neo cho phần đầu (tức là ^) của một chuỗi và là một đối sánh phân biệt chữ hoa chữ thường "
Ryan Schumacher

2
Với Mongoose, điều này phù hợp với tôi: User.find ({'username': {$ regex: new RegExp ('^' + username.toLowerCase (), 'i')}}, function (err, res) {if (err ) ném sai; tiếp theo (null, res);});
ChrisRich

5
Đừng bao giờ quên thoát khỏi tên khi làm việc với biểu thức chính quy. Chúng tôi không muốn tiêm để chiếm lấy vẻ đẹp của mongodb. Chỉ cần tưởng tượng bạn đã sử dụng mã này cho một trang đăng nhập và tên người dùng là ".*".
Tobias

90

Bạn cần phải sử dụng một biểu thức chính quy không phân biệt chữ hoa chữ thường cho biểu thức này, ví dụ:

db.collection.find( { "name" : { $regex : /Andrew/i } } );

Để sử dụng mẫu regex từ thenamebiến của bạn , hãy tạo một đối tượng RegExp mới :

var thename = "Andrew";
db.collection.find( { "name" : { $regex : new RegExp(thename, "i") } } );

Cập nhật: Để đối sánh chính xác, bạn nên sử dụng regex "name": /^Andrew$/i. Cảm ơn Yannick L.


7
Bạn có biết cách sử dụng Node.js mongoose không?
user847495,

1
Tôi tự hỏi điều này sẽ hoạt động tốt như thế nào với các bộ sưu tập lớn. Bạn sẽ mất lợi ích của một chức năng sắp xếp
Wilfred Springer

5
Điều này là sai, nó sẽ khớp với bất kỳ tài liệu nào có chứa "andrew" cho name, không chỉ bằng.
Jonathan Cremin

14
@JonathanCremin để giúp những người bạn nên đăng câu trả lời chính xác:{ "name": /^Andrew$/i }
Yannick Loriot

@YannickL. 1+ để làm điều thông thường. Tôi chỉ đi ngang qua không phải những gì tôi đang tìm kiếm.
Lpc_dark

38

Tôi đã giải quyết nó như thế này.

 var thename = 'Andrew';
 db.collection.find({'name': {'$regex': thename,$options:'i'}});

Nếu bạn muốn truy vấn về 'đối sánh chính xác không phân biệt chữ hoa chữ thường' thì bạn có thể làm như thế này.

var thename =  '^Andrew$';
db.collection.find({'name': {'$regex': thename,$options:'i'}});

7

MongoDB 3.4 hiện bao gồm khả năng tạo chỉ mục phân biệt chữ hoa chữ thường thực sự, điều này sẽ làm tăng tốc độ tra cứu phân biệt chữ hoa chữ thường trên các tập dữ liệu lớn. Nó được thực hiện bằng cách chỉ định một đối chiếu có cường độ là 2.

Có lẽ cách dễ nhất để làm điều đó là thiết lập đối chiếu trên cơ sở dữ liệu. Sau đó, tất cả các truy vấn kế thừa đối chiếu đó và sẽ sử dụng nó:

db.createCollection("cities", { collation: { locale: 'en_US', strength: 2 } } )
db.names.createIndex( { city: 1 } ) // inherits the default collation

Bạn cũng có thể làm như thế này:

db.myCollection.createIndex({city: 1}, {collation: {locale: "en", strength: 2}});

Và sử dụng nó như thế này:

db.myCollection.find({city: "new york"}).collation({locale: "en", strength: 2});

Điều này sẽ trả về các thành phố có tên "new york", "New York", "New york", v.v.

Để biết thêm thông tin: https://jira.mongodb.org/browse/SERVER-90


cường độ: 1 là đủ để lập chỉ mục không phân biệt chữ hoa chữ thường, dấu phụ. docs.mongodb.com/manual/reference/collation
Gaurav Ragtah

7
  1. Với Mongoose (và Node), điều này đã hoạt động:

    • User.find({ email: /^name@company.com$/i })

    • User.find({ email: new RegExp(`^ $ {emailVariable} $`, 'i')})

  2. Trong MongoDB, điều này đã hoạt động:

    • db.users.find({ email: { $regex: /^name@company.com$/i }})

Cả hai dòng đều không phân biệt chữ hoa chữ thường. Email trong DB có thể là NaMe@CompanY.Comvà cả hai dòng sẽ vẫn tìm thấy đối tượng trong DB.

Tương tự như vậy, chúng tôi có thể sử dụng /^NaMe@CompanY.Com$/ivà nó vẫn sẽ tìm thấy email: name@company.comtrong DB.


5

Để tìm chuỗi không phân biệt chữ hoa chữ thường, hãy sử dụng cái này,

var thename = "Andrew";
db.collection.find({"name":/^thename$/i})

1
Tại sao các bạn thêm một câu trả lời trùng lặp vì nó đã có trong stackoverflow.com/a/7101868/4273915
Shrabanee

4

Tôi vừa giải quyết vấn đề này một vài giờ trước.

var thename = 'Andrew'
db.collection.find({ $text: { $search: thename } });
  • Độ nhạy chữ hoa chữ thường và dấu phụ được đặt thành false theo mặc định khi thực hiện truy vấn theo cách này.

Bạn thậm chí có thể mở rộng điều này bằng cách chọn trên các trường bạn cần từ đối tượng người dùng của Andrew bằng cách thực hiện theo cách này:

db.collection.find({ $text: { $search: thename } }).select('age height weight');

Tham khảo: https://docs.mongodb.org/manual/reference/operator/query/text/#text


1
$ text thực hiện tìm kiếm văn bản trên nội dung của các trường được lập chỉ mục bằng chỉ mục văn bản.
SSH này

4

... với mongoose trên NodeJS rằng truy vấn:

const countryName = req.params.country;

{ 'country': new RegExp(`^${countryName}$`, 'i') };

hoặc là

const countryName = req.params.country;

{ 'country': { $regex: new RegExp(`^${countryName}$`), $options: 'i' } };

// ^australia$

hoặc là

const countryName = req.params.country;

{ 'country': { $regex: new RegExp(`^${countryName}$`, 'i') } };

// ^turkey$

Một ví dụ mã đầy đủ trong Javascript, NodeJS với Mongoose ORM trên MongoDB

// get all customers that given country name
app.get('/customers/country/:countryName', (req, res) => {
    //res.send(`Got a GET request at /customer/country/${req.params.countryName}`);

    const countryName = req.params.countryName;

    // using Regular Expression (case intensitive and equal): ^australia$

    // const query = { 'country': new RegExp(`^${countryName}$`, 'i') };
    // const query = { 'country': { $regex: new RegExp(`^${countryName}$`, 'i') } };
    const query = { 'country': { $regex: new RegExp(`^${countryName}$`), $options: 'i' } };

    Customer.find(query).sort({ name: 'asc' })
        .then(customers => {
            res.json(customers);
        })
        .catch(error => {
            // error..
            res.send(error.message);
        });
});

1

Truy vấn sau đây sẽ tìm các tài liệu có chuỗi bắt buộc một cách thiếu tế nhị và xuất hiện trên toàn cầu

db.collection.find({name:{
                             $regex: new RegExp(thename, "ig")
                         }
                    },function(err, doc) {
                                         //Your code here...
                  });

1

Để tìm chuỗi chữ không phân biệt chữ hoa chữ thường:

Sử dụng regex (được khuyến nghị)

db.collection.find({
    name: {
        $regex: new RegExp('^' + name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '$', 'i')
    }
});

Sử dụng chỉ mục chữ thường (nhanh hơn)

db.collection.find({
    name_lower: name.toLowerCase()
});

Biểu thức chính quy chậm hơn so với đối sánh chuỗi theo nghĩa đen. Tuy nhiên, một trường chữ thường bổ sung sẽ làm tăng độ phức tạp cho mã của bạn. Khi nghi ngờ, hãy sử dụng biểu thức chính quy. Tôi khuyên bạn chỉ nên sử dụng trường viết thường rõ ràng nếu nó có thể thay thế trường của bạn, tức là ngay từ đầu bạn không quan tâm đến trường hợp này.

Lưu ý rằng bạn sẽ cần phải thoát khỏi tên trước regex. Nếu bạn muốn ký tự đại diện do người dùng nhập, hãy thích thêm vào .replace(/%/g, '.*')sau khi thoát để bạn có thể so khớp "a%" để tìm tất cả các tên bắt đầu bằng 'a'.


1

Bạn có thể sử dụng Chỉ mục phân biệt chữ hoa chữ thường :

Ví dụ sau đây tạo một tập hợp không có đối chiếu mặc định, sau đó thêm chỉ mục vào trường tên với đối chiếu không phân biệt chữ hoa chữ thường. Các thành phần quốc tế cho Unicode

/*
* strength: CollationStrength.Secondary
* Secondary level of comparison. Collation performs comparisons up to secondary * differences, such as diacritics. That is, collation performs comparisons of 
* base characters (primary differences) and diacritics (secondary differences). * Differences between base characters takes precedence over secondary 
* differences.
*/
db.users.createIndex( { name: 1 }, collation: { locale: 'tr', strength: 2 } } )

Để sử dụng chỉ mục, các truy vấn phải chỉ định cùng một đối chiếu.

db.users.insert( [ { name: "Oğuz" },
                            { name: "oğuz" },
                            { name: "OĞUZ" } ] )

// does not use index, finds one result
db.users.find( { name: "oğuz" } )

// uses the index, finds three results
db.users.find( { name: "oğuz" } ).collation( { locale: 'tr', strength: 2 } )

// does not use the index, finds three results (different strength)
db.users.find( { name: "oğuz" } ).collation( { locale: 'tr', strength: 1 } )

hoặc bạn có thể tạo một bộ sưu tập với đối chiếu mặc định:

db.createCollection("users", { collation: { locale: 'tr', strength: 2 } } )
db.users.createIndex( { name : 1 } ) // inherits the default collation

-3

Một cách dễ dàng sẽ là sử dụng $ toLower như bên dưới.

db.users.aggregate([
    {
        $project: {
            name: { $toLower: "$name" }
        }
    },
    {
        $match: {
            name: the_name_to_search
        }
    }
])
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.