Mongodb에서 대소 문자를 구분하지 않는 쿼리를 작성하려면 어떻게해야합니까?


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

대소 문자를 구분하지 않는 쿼리는 어떻게합니까? "andrew"라고해도 결과를 찾고 싶습니다.



정규식과 관련된 답변을 사용하려는 모든 사람에게 참고 : 정규식은 삭제해야합니다.
sean

답변:


126

Chris Fulstow의 솔루션은 작동하지만 (+1), 특히 컬렉션이 매우 큰 경우 효율적이지 않을 수 있습니다. 루트가 아닌 정규 표현식 (로 시작하지 않는 ^정규 표현식, 문자열의 시작 부분에 정규 표현식을 고정 함) 및 i대소 문자를 구분하지 않는 플래그를 사용하는 정규 표현식 은 존재하더라도 색인을 사용하지 않습니다.

고려할 수있는 다른 옵션은 name필드 의 소문자 버전을 저장하기 위해 데이터를 비정규 화하는 것 입니다 (예 : name_lower. 그런 다음 다음과 같이 대소 문자를 구분하지 않는 정확한 일치에 대해 효율적으로 (특히 색인화 된 경우) 쿼리 할 수 ​​있습니다.

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

또는 다음과 같이 접두사 일치 (루팅 된 정규식)를 사용합니다.

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

이 두 쿼리는 모두에 인덱스를 사용합니다 name_lower.


1
좋은 대답, 내 정규식 접근 방식은 수백만 개의 문서를 스캔해야하면 정말 느려집니다.
Chris Fulstow

34
"Andrew"를 찾는 동안 "Andrew something"을 찾을 수 있기 때문에 이것은 실제로 완전히 정확하지 않습니다. 따라서 정규식을 다음 new RegExp('^'+ username + '$', "i")과 같이 조정하십시오 .
Tarion 2014-01-21

9
MongoDB 웹 사이트에 따르면 대소 문자를 구분하지 않는 정규식은 인덱스 효율적이지 않습니다. "$ regex는 정규식에 문자열의 시작 (예 : ^)에 대한 앵커가 있고 대소 문자를 구분하는 일치 일 때만 인덱스를 효율적으로 사용할 수 있습니다. "
Ryan Schumacher

2
Mongoose를 사용하면 다음과 같이 작동했습니다. User.find ({ 'username': {$ regex : new RegExp ( '^'+ username.toLowerCase (), 'i')}}, function (err, res) {if (err ) throw err; next (null, res);});
ChrisRich

5
정규식으로 작업 할 때 이름을 이스케이프하는 것을 잊지 마십시오. 우리는 주사가 mongodb의 아름다움을 차지하는 것을 원하지 않습니다. 로그인 페이지에이 코드를 사용했고 사용자 이름은 ".*".
Tobias

90

이 경우 대소 문자를 구분하지 않는 정규식 을 사용해야합니다 . 예 :

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

thename변수 에서 정규식 패턴을 사용하려면 새 RegExp 개체를 생성 합니다.

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

업데이트 : 정확히 일치하려면 regex를 사용해야합니다 "name": /^Andrew$/i. Yannick L.


7
Node.js mongoose를 사용하여이 작업을 수행하는 방법을 알고 있습니까?
user847495 aug.

1
이것이 대규모 컬렉션에서 얼마나 잘 작동하는지 궁금합니다. 당신은 정렬 functinon의 이익 느슨한 것
윌프레드 스프링

5
이것은 잘못된 것입니다 . 단지 같음이 아니라에 대해 "andrew"를 포함하는 모든 문서와 일치합니다 name.
Jonathan Cremin 2014

14
: 도움말 사람들에게 @JonathanCremin하면 정답 게시한다{ "name": /^Andrew$/i }
야닉 Loriot

@YannickL. 상식적인 일을하기위한 1+. 나는 내가 찾던 것이 아니라 그냥 지나가고 있었다.
Lpc_dark

38

나는 이것을 이렇게 해결했다.

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

'대소 문자를 구분하지 않는 정확히 일치'에 대해 쿼리하려면 다음과 같이 갈 수 있습니다.

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

7

이제 MongoDB 3.4에는 대소 문자를 구분하지 않는 진정한 인덱스를 만드는 기능이 포함되어있어 대규모 데이터 세트에서 대소 문자를 구분하지 않는 조회 속도를 크게 높일 수 있습니다. 강도가 2 인 데이터 정렬을 지정하여 만들어집니다.

아마도 가장 쉬운 방법은 데이터베이스에 데이터 정렬을 설정하는 것입니다. 그런 다음 모든 쿼리가 해당 데이터 정렬을 상속하고이를 사용합니다.

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

다음과 같이 할 수도 있습니다.

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

다음과 같이 사용하십시오.

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

이렇게하면 '뉴욕', '뉴욕', '뉴욕'등의 도시가 반환됩니다.

자세한 정보 : https://jira.mongodb.org/browse/SERVER-90


strength : 1은 대소 문자를 구분하지 않고 분음 부호를 구분하지 않는 인덱싱에 충분합니다. docs.mongodb.com/manual/reference/collation
Gaurav Ragtah

7
  1. Mongoose (및 Node)를 사용하면 다음과 같이 작동했습니다.

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

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

  2. MongoDB에서는 다음과 같이 작동했습니다.

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

두 줄은 모두 대소 문자를 구분하지 않습니다. DB의 이메일이 될 수 NaMe@CompanY.Com있으며 두 줄 모두 DB에서 개체를 찾습니다.

마찬가지로, 우리 는 DB에서 /^NaMe@CompanY.Com$/i이메일을 사용할 수 있습니다 name@company.com.


5

대소 문자를 구분하지 않는 문자열을 찾으려면 이것을 사용하십시오.

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

1
그것은 이미 존재하는 한 당신은 왜 중복 대답을 추가 stackoverflow.com/a/7101868/4273915
Shrabanee

4

이 문제를 몇 시간 전에 해결했습니다.

var thename = 'Andrew'
db.collection.find({ $text: { $search: thename } });
  • 이러한 방식으로 쿼리를 수행 할 때 대소 문자 구분 및 분음 부호 구분은 기본적으로 false로 설정됩니다.

다음과 같은 방법으로 Andrew의 사용자 개체에서 필요한 필드를 선택하여이를 확장 할 수도 있습니다.

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

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


1
$ text는 텍스트 인덱스로 인덱싱 된 필드의 내용에 대해 텍스트 검색을 수행합니다.
SSH This

4

... NodeJS에서 mongoose를 사용하여 다음을 쿼리합니다.

const countryName = req.params.country;

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

또는

const countryName = req.params.country;

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

// ^australia$

또는

const countryName = req.params.country;

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

// ^turkey$

MongoDB에서 Mongoose ORM을 사용하는 Javascript, NodeJS의 전체 코드 예제

// 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

다음 쿼리는 필수 문자열이 둔감하고 전역 발생이 있는 문서를 찾습니다.

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

1

대소 문자를 구분하지 않는 리터럴 문자열을 찾으려면 :

정규식 사용 (권장)

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

소문자 색인 사용 (빠름)

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

정규식은 리터럴 문자열 일치보다 느립니다. 그러나 추가 소문자 필드는 코드 복잡성을 증가시킵니다. 확실하지 않은 경우 정규식을 사용하십시오. 필드를 대체 할 수있는 경우에만 명시 적으로 소문자 필드를 사용하는 것이 좋습니다. 즉, 처음에는 대소 문자를 신경 쓰지 않습니다.

정규식 전에 이름을 이스케이프해야합니다. 사용자 입력 와일드 카드를 원하는 경우 .replace(/%/g, '.*')"a"로 시작하는 모든 이름을 찾기 위해 "a %"와 일치 할 수 있도록 이스케이프 후 추가 하는 것이 좋습니다.


1

대소 문자를 구분하지 않는 색인을 사용할 수 있습니다 .

다음 예제에서는 기본 데이터 정렬이없는 컬렉션을 만든 다음 대소 문자를 구분하지 않는 데이터 정렬을 사용하여 이름 필드에 인덱스를 추가합니다. 유니 코드 용 국제 구성 요소

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

인덱스를 사용하려면 쿼리에서 동일한 데이터 정렬을 지정해야합니다.

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

또는 기본 데이터 정렬로 컬렉션을 만들 수 있습니다.

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

-3

쉬운 방법은 아래와 같이 $ toLower를 사용하는 것입니다.

db.users.aggregate([
    {
        $project: {
            name: { $toLower: "$name" }
        }
    },
    {
        $match: {
            name: the_name_to_search
        }
    }
])
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.