programing

MongoDB: 대소문자를 구분하지 않는 쿼리를 작성할 수 있습니까?

golfzon 2023. 4. 4. 22:36
반응형

MongoDB: 대소문자를 구분하지 않는 쿼리를 작성할 수 있습니까?

예:

> db.stuff.save({"foo":"bar"});

> db.stuff.find({"foo":"bar"}).count();
1
> db.stuff.find({"foo":"BAR"}).count();
0

정규식이 필요하겠군

이 예에서는 다음과 같습니다.

db.stuff.find( { foo: /^bar$/i } );

단, 매번 추가 비용을 부담하지 말고 도입할 때 가격을 다운케이스(또는 업케이스)할 수도 있습니다.물론 이것은 사람들의 이름이나 그런 것에는 적용되지 않지만, 태그와 같은 사용 예에 해당될 수 있습니다.

갱신:

원래의 답은 이제 쓸모없게 되었다.Mongodb는 많은 기능을 갖춘 고급 전문 검색을 지원합니다.

원래 답변:

regex의 대소문자를 구분하지 않는 /i를 사용하여 검색하면 mongodb는 인덱스로 검색할 수 없으므로 대규모 데이터 세트에 대한 쿼리는 시간이 오래 걸릴 수 있습니다.

데이터셋이 작더라도 효율은 그다지 높지 않습니다.쿼리 보증보다 훨씬 더 큰 CPU 타격을 입게 되며, 이는 확장을 시도하면 문제가 될 수 있습니다.

또는 대문자 복사본을 저장하고 이에 대해 검색할 수 있습니다.예를 들어, 사용자 테이블에는 대소문자가 혼재된 사용자 이름이 있지만 ID는 사용자 이름의 대문자 복사본입니다.이렇게 하면 대소문자를 구분하는 중복이 불가능하며("foo"와 "foo"를 모두 사용할 수 없음) ID = username.toUpperCase()로 검색하여 대소문자를 구분하지 않는 사용자 이름을 검색할 수 있습니다.

메시지 본문 등 필드가 큰 경우 데이터 복제는 권장되지 않습니다.이 경우 Apache Lucene과 같은 외부 인덱서를 사용하는 것이 가장 좋은 선택이라고 생각합니다.

MongoDB 3.4부터는 대소문자를 구분하지 않는 빠른 검색을 수행하려면 대소문자를 구분하지 않는 인덱스를 사용하는 것이 좋습니다.

창업자 중 한 명에게 직접 이메일을 보내서 이 작업을 수행해 달라고 요청했더니 그가 해줬어요!2009년부터 JIRA에서 발행되고 있으며, 많은 사람들이 이 기능을 요청하고 있습니다.동작 방법은 다음과 같습니다.

대소문자를 구분하지 않는 지수는 강도가 1 또는 2인 조합을 지정함으로써 작성된다.대소문자를 구분하지 않는 인덱스를 다음과 같이 작성할 수 있습니다.

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

또한 수집을 생성할 때 수집별로 기본 데이터 정렬을 지정할 수도 있습니다.

db.createCollection('cities', { collation: { locale: 'en', strength: 2 } } );

하지 않는 인덱스를 하려면 대소문자를 구분하지 않는 을 '대소문자를 구분하지 않는다'로 .find인덱스 또는 컬렉션을 만들 때 사용된 작업:

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

그러면 "뉴욕", "뉴욕", "뉴욕" 등이 반환됩니다.

기타 주의사항

  • 이 경우 전체 텍스트 검색을 사용하도록 제안하는 답변이 잘못되어 위험할 수 있습니다.질문은 대소문자를 구분하지 않는 쿼리를 만드는 것이었습니다.username: 'bill'BILL ★★★★★★★★★★★★★★★★★」Bill, 전체 텍스트 검색 쿼리가 아닙니다.이 검색 쿼리는 의 줄임말과도 일치합니다.bill 「」, 「」등입니다.Bills,billedsyslog.

  • 인덱스를 사용하더라도 문서에 다음과 같은 내용이 기재되어 있기 때문에 정규 표현을 사용하는 것을 권장하는 답변이 느립니다.

    "대소문자를 구분하지 않는 정규식 쿼리는 일반적으로 인덱스를 효과적으로 사용할 수 없습니다.$regex 구현은 데이터 정렬을 인식하지 않으며 대소문자를 구분하지 않는 인덱스를 사용할 수 없습니다."

    $regex응답에는 사용자 입력 주입의 위험도 있습니다.

변수에서 regexp를 작성해야 하는 경우에는 https://stackoverflow.com/a/10728069/309514 를 사용하는 것이 훨씬 더 좋습니다.

그런 다음 다음과 같은 작업을 수행할 수 있습니다.

var string = "SomeStringToFind";
var regex = new RegExp(["^", string, "$"].join(""), "i");
// Creates a regex of: /^SomeStringToFind$/i
db.stuff.find( { foo: regex } );

이 기능은 프로그램성이 향상되거나 자주 사용하는 경우 미리 컴파일하여 성능을 향상시킬 수 있다는 장점이 있습니다.

앞의 예는 다음과 같습니다.

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

bar를 포함하는 모든 엔트리가 쿼리(bar1, barxyz, openbar)와 일치합니다.인증함수에서의 사용자명 검색은 매우 위험할 수 있습니다.

다음과 같이 적절한 regexp 구문을 사용하여 검색어만 일치시켜야 할 수 있습니다.

db.stuff.find( { foo: /^bar$/i } );

정규 표현의 구문 도움말에 대해서는, http://www.regular-expressions.info/ 를 참조해 주세요.

db.company_profile.find({ "companyName" : { "$regex" : "Nilesh" , "$options" : "i"}});
db.zipcodes.find({city : "NEW YORK"}); // Case-sensitive
db.zipcodes.find({city : /NEW york/i}); // Note the 'i' flag for case-insensitivity

TL;DR

mongo에서의 올바른 방법

RegExp 사용 안 함

자연스러운 조작과 mongodb에 내장된 인덱싱을 사용하여 검색

순서 1:

db.articles.insert(
   [
     { _id: 1, subject: "coffee", author: "xyz", views: 50 },
     { _id: 2, subject: "Coffee Shopping", author: "efg", views: 5 },
     { _id: 3, subject: "Baking a cake", author: "abc", views: 90  },
     { _id: 4, subject: "baking", author: "xyz", views: 100 },
     { _id: 5, subject: "Café Con Leche", author: "abc", views: 200 },
     { _id: 6, subject: "Сырники", author: "jkl", views: 80 },
     { _id: 7, subject: "coffee and cream", author: "efg", views: 10 },
     { _id: 8, subject: "Cafe con Leche", author: "xyz", views: 10 }
   ]
)
 

순서 2:

검색할 TEXT 필드에 인덱스를 작성해야 합니다.인덱스 쿼리를 작성하지 않으면 매우 느려집니다.

db.articles.createIndex( { subject: "text" } )

순서 3:

db.articles.find( { $text: { $search: "coffee",$caseSensitive :true } } )  //FOR SENSITIVITY
db.articles.find( { $text: { $search: "coffee",$caseSensitive :false } } ) //FOR INSENSITIVITY


 

Regex 기반 쿼리를 사용할 때 유의해야 할 한 가지 매우 중요한 사항 - 로그인 시스템에 대해 이 작업을 수행할 때는 검색하는 모든 문자를 이스케이프하고 ^ 및 $ 연산자를 잊지 마십시오.Lodash에는 이 기능을 위한 훌륭한 기능이 있습니다. 이미 사용 중인 경우:

db.stuff.find({$regex: new RegExp(_.escapeRegExp(bar), $options: 'i'})

왜일까요? 어떤 사용자가.*사용자명으로 사용합니다.모든 사용자 이름과 일치하므로 사용자의 비밀번호를 추측하는 것만으로 로그인을 할 수 있습니다.

"Table"에서 "column"을 검색하고 대소문자를 구분하지 않는 검색을 수행한다고 가정합니다.최선의 효율적인 방법은 다음과 같습니다.

//create empty JSON Object
mycolumn = {};

//check if column has valid value
if(column) {
    mycolumn.column = {$regex: new RegExp(column), $options: "i"};
}
Table.find(mycolumn);

검색 값을 RegEx로 추가하고 "i" 옵션을 사용하여 둔감한 기준으로 검색합니다.

Mongo(현재 버전 2.0.0)에서는 인덱스된 필드에 대해 대소문자를 구분하지 않는 검색을 허용하지 않습니다. 해당 문서를 참조하십시오.색인화되지 않은 필드의 경우 다른 응답에 나열된 정규식이 좋습니다.

변수 검색 및 이스케이프:

const escapeStringRegexp = require('escape-string-regexp')
const name = 'foo'
db.stuff.find({name: new RegExp('^' + escapeStringRegexp(name) + '$', 'i')})   

변수를 이스케이프하면 에 의한 공격으로부터 쿼리를 보호할 수 있습니다.*' 또는 기타 정규식.

escape-string-regexp

최적의 방법은 선택한 언어로 오브젝트 모델래퍼를 작성할 때 save() 메서드를 인덱스를 붙이는 일련의 필드에서도 반복하는 것입니다.이러한 필드 세트에는 검색에 사용되는 소문자가 포함되어 있어야 합니다.

오브젝트가 다시 저장될 때마다 소문자 속성이 체크되고 기본 속성에 대한 변경 사항이 반영되어 업데이트됩니다.이를 통해 효율적으로 검색할 수 있지만 매번 lc 필드를 업데이트하기 위해 필요한 추가 작업을 숨길 수 있습니다.

소문자 필드는 key:value object store 또는 접두사 lc_가 붙은 필드 이름일 수 있습니다.두 번째 쿼리를 사용하여 쿼리를 간소화합니다(심층 객체 쿼리는 때때로 혼란을 일으킬 수 있습니다).

주의: lc_필드의 기반이 되는 메인필드가 아닌 lc_필드의 인덱스를 작성해야 합니다.

Mongoose를 사용하면 효과가 있었습니다.

var find = function(username, next){
    User.find({'username': {$regex: new RegExp('^' + username, 'i')}}, function(err, res){
        if(err) throw err;
        next(null, res);
    });
}

MongoDB 나침반을 사용하는 경우:

컬렉션으로 이동합니다.필터 입력 -> {Fieldname: /string/i}

Mongoose를 사용하는 Node.js의 경우:

Model.find ({FieldName: {$regex: "stringToSearch", $options: "i"})

집약 프레임워크는 mongodb 2.2에서 도입되었습니다.문자 연산자 "$strcasecmp"를 사용하여 문자열 간에 대소문자를 구분하지 않습니다.regex를 사용하는 것보다 더 권장되고 쉽습니다.

aggregation 명령어 연산자에 관한 공식 문서(https://docs.mongodb.com/manual/reference/operator/aggregation/strcasecmp/ #exp._S_strcasecmp)는 다음과 같습니다.

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

다음 예제에서는 기본 조회가 없는 컬렉션을 작성한 후 대소문자를 구분하지 않는 조회를 사용하여 이름 필드에 인덱스를 추가하는 방법을 보여 줍니다.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 } } )

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

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

아무도 정규식 주입의 위험성에 대해 경고하지 않았다니 놀랍네요/^bar$/i바(bar)가 비밀번호 또는 계정 ID 검색인 경우.bar => .*@myhackeddomain.com를 들어 PERL에서 제공되는 regex\E 특수 문자 사용!

db.stuff.find( { foo: /^\Qbar\E$/i } );

이스케이프 막대 변수를 사용해야 합니다.\와 함께 탄다.\\피하다\E예를 들어 다음과 같은 경우에 다시 악용합니다. bar = '\E.*@myhackeddomain.com\Q'

또 다른 옵션은 여기에 설명된 바와 같이 Perl의 \Q...\E 또는 quotemeta()동등한 Javascript를 사용하는 것입니다.

RegExp를 사용합니다.다른 옵션이 마음에 들지 않는 경우 RegExp를 사용하는 것이 좋습니다.문자열 대소문자를 구분하지 않습니다.

var username = new RegExp("^" + "John" + "$", "i");;

쿼리에서 사용자 이름을 사용하면 완료됩니다.

당신에게도 효과가 있기를 바랍니다.행운을 빌어요.

쿼리에 특수 문자가 있는 경우 regex simple은 작동하지 않습니다.당신은 그 특수 캐릭터들을 피할 필요가 있을 것입니다.

서드파티 라이브러리를 인스톨 하지 않아도, 다음의 도우미 기능을 이용할 수 있습니다.

const escapeSpecialChars = (str) => {
  return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
}

질문 내용은 다음과 같습니다.

db.collection.find({ field: { $regex: escapeSpecialChars(query), $options: "i" }})

도움이 되었으면 좋겠다!

C#에서는 필터를 사용하는 것이 좋습니다.

string s = "searchTerm";
    var filter = Builders<Model>.Filter.Where(p => p.Title.ToLower().Contains(s.ToLower()));
                var listSorted = collection.Find(filter).ToList();
                var list = collection.Find(filter).ToList();

반품 후에 메서드가 호출된다고 생각하기 때문에 인덱스를 사용할 수도 있지만 아직 테스트하지 않았습니다.

이것에 의해, 다음의 문제도 회피됩니다.

var filter = Builders<Model>.Filter.Eq(p => p.Title.ToLower(), s.ToLower());

그 몽고브는 p라고 생각할거야Title.ToLower()는 속성이며 올바르게 매핑되지 않습니다.

저도 비슷한 문제에 직면했었고, 제게는 다음과 같은 이점이 있었습니다.

  const flavorExists = await Flavors.findOne({
    'flavor.name': { $regex: flavorName, $options: 'i' },
  });

대소문자를 구분하지 않는 regex용 간단한 Func를 만들었습니다.필터에 사용합니다.

private Func<string, BsonRegularExpression> CaseInsensitiveCompare = (field) => 
            BsonRegularExpression.Create(new Regex(field, RegexOptions.IgnoreCase));

그런 다음 다음과 같이 필드를 필터링합니다.

db.stuff.find({"foo": CaseInsensitiveCompare("bar")}).count();

문자열 검색을 위해 테스트되었습니다.

{'_id': /.*CM.*/}               ||find _id where _id contains   ->CM
{'_id': /^CM/}                  ||find _id where _id starts     ->CM
{'_id': /CM$/}                  ||find _id where _id ends       ->CM

{'_id': /.*UcM075237.*/i}       ||find _id where _id contains   ->UcM075237, ignore upper/lower case
{'_id': /^UcM075237/i}          ||find _id where _id starts     ->UcM075237, ignore upper/lower case
{'_id': /UcM075237$/i}          ||find _id where _id ends       ->UcM075237, ignore upper/lower case

Golang을 사용하여 mongodb와 mgo godoc globalsign 라이브러리를 사용하여 대소문자를 구분하는 전문 검색을 원하는 사용자.

collation := &mgo.Collation{
    Locale:   "en",
    Strength: 2, 
}


err := collection.Find(query).Collation(collation)

mongo 문서에서 볼 수 있듯이 버전 3.2 이후$textindex는 기본적으로 대소문자를 구분하지 않습니다.https://docs.mongodb.com/manual/core/index-text/ #text-index-case-competitivity

텍스트 인덱스를 만들고 쿼리에서 $text 연산자를 사용합니다.

언급URL : https://stackoverflow.com/questions/1863399/mongodb-is-it-possible-to-make-a-case-insensitive-query

반응형