HOWTO · MongoDB

MongoDB에서 문자열 길이를 사용한 쿼리

이 튜토리얼에서는 MongoDB에서 문자열 길이로 쿼리하는 방법에 대해 설명합니다.

이 페이지의 내용

문자열 필드의 길이가 유니코드 코드 포인트 기준으로 정확히 5인 MongoDB 문서를 찾으려면 find()에서 $expr와 $strLenCP를 사용합니다. db.mydata.find({ $expr: { $eq: [{ $strLenCP: "$Name" }, 5] } }). 이 간단한 쿼리는 모든 문서의 Name 필드가 문자열이라고 가정합니다. 필드 유형이 섞여 있을 때 사용할 수 있는 보호된 형태는 아래에 나옵니다.

MongoDB에서 문자열 길이로 문서 찾기

방법을 비교할 때는 하나의 컬렉션과 일관된 필드명을 사용하세요. 다음 독립 실행형 JavaScript 예제는 샘플 문서 6개를 만들고 코드 포인트 길이를 기준으로 로컬에서 필터링합니다. 데이터베이스 연결이 필요하지 않으며 MongoDB 서버에서 실행되는 예제는 아닙니다.

이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

const documents = [
  { _id: 1, Name: "hello" },
  { _id: 2, Name: "world" },
  { _id: 3, Name: "abcdefgh" },
  { _id: 4, Name: "ijklmnop" },
  { _id: 5, Name: "apple" },
  { _id: 6, Name: "grape" }
];
const matches = documents.filter(document => [...document.Name].length === 5);
console.log(JSON.stringify(matches, null, 2));
[
  {
    "_id": 1,
    "Name": "hello"
  },
  {
    "_id": 2,
    "Name": "world"
  },
  {
    "_id": 5,
    "Name": "apple"
  },
  {
    "_id": 6,
    "Name": "grape"
  }
]

이 데이터에서 코드 포인트가 5개인 문서는 1, 2, 5, 6번입니다. 문자열은 각각 hello, world, apple, grape입니다. 3번과 4번 문서는 각각 코드 포인트가 8개입니다.

이 글의 데이터베이스 명령은 실행되지 않은 MongoDB 셸 예제이며, 연결된 MongoDB 서버가 있어야 합니다. 새 mydata 컬렉션에 샘플을 만들려면 db.mydata.insertMany([{ _id: 1, Name: "hello" }, { _id: 2, Name: "world" }, { _id: 3, Name: "abcdefgh" }, { _id: 4, Name: "ijklmnop" }, { _id: 5, Name: "apple" }, { _id: 6, Name: "grape" }])를 사용하세요. 기존 _id와 충돌하지 않도록 별도의 샘플 컬렉션을 사용하세요.

$where로 문자열 길이 필터링

$where 쿼리 연산자는 서버 측 JavaScript를 평가합니다. 해당 문서에는 배포 환경의 제한과 서버 측 스크립팅을 활성화해야 한다는 요구사항이 설명되어 있습니다. 서버 측 JavaScript를 사용할 수 있다면 다음 쿼리로 샘플을 필터링할 수 있습니다. db.mydata.find({ $where: function () { return typeof this.Name === "string" && this.Name.length === 5; } }).

유형 검사는 필드가 없거나 값이 null이거나 문자열이 아닌 경우 이를 건너뜁니다. 5보다 큰 길이를 찾으려면 === 5를 > 5로 바꾸세요. JavaScript의 .length는 UTF-16 코드 단위 수를 셉니다. 기본 다국어 평면 바깥의 이모지는 코드 단위 두 개를 차지합니다. 따라서 이 방법은 ASCII 샘플에서는 다른 예제와 같은 결과를 내지만, 코드 포인트를 세는 일반적인 대체 방법은 아닙니다. 서버 측 JavaScript 없이 조건을 표현하려면 $expr를 사용하세요.

find()에서 $expr와 $strLenCP 사용

$expr 연산자를 사용하면 find()에서 집계 표현식을 평가할 수 있습니다. $strLenCP는 유니코드 코드 포인트를 세고, $eq는 그 개수를 지정한 값과 비교합니다. 길이가 5보다 큰 문자열을 찾으려면 $eq를 $gt로 바꾸고, 5도 포함하려면 $gte로 바꾸세요.

$strLenCP 문서에 설명된 것처럼 입력값은 문자열이어야 합니다. null이거나 존재하지 않는 입력값을 사용하면 오류가 발생합니다. Name의 유형이 문자열이 아닐 수도 있다면 조건식을 사용하세요.

db.mydata.find({ $expr: { $cond: [{ $eq: [{ $type: "$Name" }, "string"] }, { $eq: [{ $strLenCP: "$Name" }, 5] }, false] } })

여기서 $cond는 문자열인 경우에만 길이를 비교하고, 그 외에는 false를 반환합니다. 빈 문자열의 길이는 0입니다. 필드가 없거나 null이면 빈 문자열로 취급하지 않고 건너뜁니다. 별도의 조건을 $and로 묶더라도 먼저 평가되어 부적절한 입력값으로부터 $strLenCP를 보호한다고 가정해서는 안 됩니다.

코드 포인트는 UTF-8 바이트 수나 눈에 보이는 문자 수와 다릅니다. 결합 악센트가 붙은 글자는 코드 포인트 두 개로 이루어집니다. 애플리케이션에 필요한 계산 기준을 선택하세요.

이 글의 공식 문서 링크는 참고용입니다. 여기서는 링크의 현재 접근 가능 여부나 최신 내용을 확인하지 않았습니다.

중첩 필드를 사용하려면 유형 검사에서도 표현식 참조를 "$parentField.childField"와 같은 점 표기 경로로 바꾸세요. 여러 필드를 필터링할 때는 전체 조건을 $and 또는 $or와 결합할 수 있습니다.

집계 파이프라인으로 문자열 길이 필터링

필터링을 더 큰 변환 작업의 일부로 수행할 때는 집계 파이프라인을 사용하세요. 샘플 컬렉션에서 다음 $match 단계는 코드 포인트가 8개인 문자열 두 개를 선택합니다.

db.mydata.aggregate([{ $match: { $expr: { $eq: [{ $strLenCP: "$Name" }, 8] } } }])

일치하는 문서는 { _id: 3, Name: "abcdefgh" }와 { _id: 4, Name: "ijklmnop" }입니다. 이 예제는 샘플처럼 입력값이 문자열이라고 가정합니다. 값의 유형이 섞여 있다면 앞 섹션의 보호된 $cond 표현식으로 $expr 값을 바꾸고 목표 길이를 8로 설정하세요. $project를 추가하면 일치하는 문서의 형태를 바꿀 수 있고, $group을 추가하면 문서를 요약할 수 있습니다.

정규 표현식으로 고정된 문자열 길이 찾기

ASCII 문자로 이루어진 샘플의 단일 문자열 필드에는 db.mydata.find({ Name: { $regex: "^.{5}$" } })를 사용할 수 있습니다. 양쪽 앵커가 일치 범위를 제한하고 {5}는 점을 다섯 번 반복하므로 1, 2, 5, 6번 문서가 선택됩니다.

공식 $regex 문서에서 관련 매칭 옵션과 앵커를 설명합니다. 임의의 텍스트에 이 패턴을 적용할 때는 주의가 필요합니다. 점은 일반적으로 줄바꿈 문자를 제외하며, $는 마지막 줄바꿈 문자 앞에서 일치할 수 있습니다. 정규 표현식 필드 조건은 배열 안의 문자열 요소와도 일치할 수 있습니다. 단일 문자열 필드에 대해 코드 포인트를 명시적으로 세려면 보호된 $strLenCP 쿼리를 사용하세요. 문자 패턴이 작업의 일부일 때는 정규 표현식을 선택하고, 효율성이나 인덱싱을 결정하기 전에 자신의 작업 부하에서 성능을 측정하세요.