Bagaimana cara membuat kueri tidak peka huruf besar / kecil di Mongodb?

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

Bagaimana cara menanyakan case insensitive? Saya ingin menemukan hasil meskipun "andrew";

pengguna847495
sumber
Catatan untuk semua orang yang akan mencoba menggunakan jawaban yang melibatkan ekspresi reguler: Ekspresi reguler perlu disterilkan.
sean

Jawaban:

126

Solusi Chris Fulstow akan berfungsi (+1), namun, mungkin tidak efisien, terutama jika koleksi Anda sangat besar. Ekspresi reguler yang tidak di-root (yang tidak diawali dengan ^, yang menambatkan ekspresi reguler ke awal string), dan ekspresi reguler yang menggunakan itanda untuk ketidaksensitifan huruf besar / kecil tidak akan menggunakan indeks, meskipun ada.

Opsi alternatif yang dapat Anda pertimbangkan adalah mendenormalisasi data Anda untuk menyimpan namebidang versi huruf kecil , misalnya sebagai name_lower. Anda kemudian dapat membuat kueri yang efisien (terutama jika diindeks) untuk pencocokan tepat tidak peka huruf besar / kecil seperti:

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

Atau dengan pencocokan awalan (ekspresi reguler yang di-root) sebagai:

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

Kedua kueri ini akan menggunakan indeks di name_lower.

dcrosta.dll
sumber
1
Jawaban yang bagus, pendekatan regex saya benar-benar melambat setelah harus memindai beberapa juta dokumen.
Chris Fulstow
34
Ini sebenarnya tidak sepenuhnya benar, karena Anda mungkin menemukan "Andrew sesuatu" saat mencari "Andrew". Jadi sesuaikan regex menjadi: new RegExp('^'+ username + '$', "i")agar sama persis.
Tarion
9
Menurut situs web MongoDB, regex yang tidak peka huruf besar / kecil tidak efisien dalam indeks "$ regex hanya dapat menggunakan indeks secara efisien ketika persamaan reguler memiliki jangkar untuk permulaan (yaitu ^) dari sebuah string dan merupakan pencocokan yang peka huruf besar / kecil "
Ryan Schumacher
2
Dengan Mongoose ini berhasil untuk saya: User.find ({'username': {$ regex: new RegExp ('^' + username.toLowerCase (), 'i')}}, function (err, res) {if (err ) melempar err; next (null, res);});
ChrisRich
5
Jangan pernah lupa untuk mengosongkan nama saat bekerja dengan ekspresi reguler. Kami tidak ingin suntikan mengambil alih keindahan mongodb. Bayangkan saja Anda menggunakan kode ini untuk halaman login dan nama penggunanya adalah ".*".
Tobias
90

Anda perlu menggunakan ekspresi reguler tidak peka huruf besar kecil untuk yang satu ini, mis

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

Untuk menggunakan pola regex dari thenamevariabel Anda , buat objek RegExp baru :

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

Update: Untuk pencocokan tepat, Anda harus menggunakan regex "name": /^Andrew$/i. Terima kasih kepada Yannick L.

Chris Fulstow
sumber
7
Apakah Anda tahu cara melakukan ini menggunakan Node.js luwak?
pengguna847495
1
Saya bertanya-tanya seberapa baik ini akan bekerja dengan koleksi besar. Anda akan kehilangan manfaat dari fungsi semacam
Wilfred Springer
5
Ini salah, itu akan cocok dengan semua dokumen yang berisi "andrew" untuk name, tidak hanya menyamakan.
Jonathan Cremin
14
@JonathanCremin untuk membantu orang yang harus Anda posting jawaban yang benar:{ "name": /^Andrew$/i }
Yannick Loriot
@Yann. 1+ untuk melakukan hal yang masuk akal. Saya hanya lewat bukan apa yang saya cari.
Lpc_dark
38

Saya telah menyelesaikannya seperti ini.

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

Jika Anda ingin menanyakan tentang 'pencocokan persis tidak peka huruf besar / kecil' maka Anda dapat melakukannya seperti ini.

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

MongoDB 3.4 sekarang menyertakan kemampuan untuk membuat indeks case-insensitive yang sebenarnya, yang secara dramatis akan meningkatkan kecepatan pencarian case-sensitive pada dataset besar. Itu dibuat dengan menentukan collation dengan kekuatan 2.

Mungkin cara termudah untuk melakukannya adalah dengan mengatur pemeriksaan pada database. Kemudian semua kueri mewarisi pemeriksaan itu dan akan menggunakannya:

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

Anda juga bisa melakukannya seperti ini:

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

Dan gunakan seperti ini:

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

Ini akan mengembalikan kota bernama "new york", "New York", "New york", dll.

Untuk info lebih lanjut: https://jira.mongodb.org/browse/SERVER-90

pengguna3413723
sumber
kekuatan: 1 cukup untuk pengindeksan tidak peka huruf besar / kecil, tidak peka diakritik. docs.mongodb.com/manual/reference/collation
Gaurav Ragtah
7
  1. Dengan Mongoose (dan Node), ini berhasil:

    • User.find({ email: /^[email protected]$/i })

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

  2. Di MongoDB, ini berhasil:

Kedua baris peka huruf besar / kecil. Email di DB bisa jadi [email protected]dan kedua baris tersebut masih akan menemukan objek di DB.

Demikian juga, kami dapat menggunakan /^[email protected]$/idan masih akan menemukan email: [email protected]di DB.

Raymond Gan
sumber
5

Untuk menemukan string case Insensitive gunakan ini,

var thename = "Andrew";
db.collection.find({"name":/^thename$/i})
Pranit
sumber
1
Mengapa Anda menambahkan jawaban duplikat karena sudah ada di stackoverflow.com/a/7101868/4273915
Shrabanee
4

Saya baru saja menyelesaikan masalah ini beberapa jam yang lalu.

var thename = 'Andrew'
db.collection.find({ $text: { $search: thename } });
  • Sensitivitas huruf besar dan sensitivitas diakritik disetel ke false secara default saat melakukan kueri dengan cara ini.

Anda bahkan dapat mengembangkannya dengan memilih bidang yang Anda butuhkan dari objek pengguna Andrew dengan cara ini:

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

Referensi: https://docs.mongodb.org/manual/reference/operator/query/text/#text

Briant Anthony
sumber
1
$ text melakukan pencarian teks pada konten bidang yang diindeks dengan indeks teks.
SSH Ini
4

... dengan luwak di NodeJS kueri itu:

const countryName = req.params.country;

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

atau

const countryName = req.params.country;

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

// ^australia$

atau

const countryName = req.params.country;

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

// ^turkey$

Contoh kode lengkap dalam Javascript, NodeJS dengan Mongoose ORM di 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);
        });
});
aygunyilmaz
sumber
1

Kueri berikut akan menemukan dokumen dengan string yang diperlukan secara tidak sensitif dan dengan kejadian global juga

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

Untuk menemukan string literal peka huruf besar kecil:

Menggunakan regex (disarankan)

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

Menggunakan indeks huruf kecil (lebih cepat)

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

Ekspresi reguler lebih lambat daripada pencocokan string literal. Namun, bidang huruf kecil tambahan akan meningkatkan kompleksitas kode Anda. Jika ragu, gunakan ekspresi reguler. Saya akan menyarankan untuk hanya menggunakan bidang huruf kecil secara eksplisit jika itu dapat menggantikan bidang Anda, yaitu, Anda tidak peduli tentang kasus di tempat pertama.

Perhatikan bahwa Anda harus keluar dari nama sebelum regex. Jika Anda menginginkan karakter pengganti masukan pengguna, lebih suka menambahkan .replace(/%/g, '.*')setelah keluar sehingga Anda dapat mencocokkan "a%" untuk menemukan semua nama yang dimulai dengan 'a'.

Yeti
sumber
1

Anda dapat menggunakan Indeks Kasus Tidak Peka :

Contoh berikut membuat koleksi tanpa pemeriksaan default, lalu menambahkan indeks pada bidang nama dengan pemeriksaan tidak peka huruf besar / kecil. Komponen Internasional untuk 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 } } )

Untuk menggunakan indeks, kueri harus menentukan pemeriksaan yang sama.

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

atau Anda dapat membuat koleksi dengan pemeriksaan default:

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

Cara yang mudah adalah dengan menggunakan $ toLower seperti di bawah ini.

db.users.aggregate([
    {
        $project: {
            name: { $toLower: "$name" }
        }
    },
    {
        $match: {
            name: the_name_to_search
        }
    }
])
pengguna2661738
sumber