0Pricing
MongoDB Academy · 강의

정규식 쿼리와 패턴 일치

문자열 필드에 정규 표현식을 적용하여 유연하게 텍스트 패턴을 검색합니다.

정규식 쿼리와 패턴 일치은(는) CoddyKit의 무료 MongoDB Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 MongoDB Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. MongoDB Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

When You Need Pattern Matching

Sometimes you need to search for documents where a string field contains, starts with, or ends with a certain pattern—but you do not know the exact value. Simple equality filters like { name: 'Alice' } only match exact strings. Regular expressions (regex) give you flexible pattern matching against string fields in MongoDB.

MongoDB supports regex through the $regex operator or by passing a JavaScript regex literal directly in a query filter. Both approaches work, with slightly different syntax for setting options like case-insensitivity.

Basic Regex Syntax in MongoDB

There are two ways to use regex in MongoDB queries:

  • JS regex literal: { name: /alice/i } — concise, flags go after the closing slash
  • $regex operator: { name: { $regex: 'alice', $options: 'i' } } — more verbose but required when combining with other operators

Both forms produce identical results. Use the JS literal syntax for simple queries; use the $regex operator form when you need to build the pattern dynamically from a string variable or combine it with other operators on the same field.

// JS regex literal - concise
db.users.find({ name: /alice/i });
// 'i' flag = case-insensitive

// $regex operator - equivalent
db.users.find({ name: { $regex: 'alice', $options: 'i' } });

// Dynamic pattern from variable:
const searchTerm = req.query.name;
const escapedTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // Escape special chars
db.users.find({ name: { $regex: escapedTerm, $options: 'i' } });

Regex Options: i, m, s, x

MongoDB supports four regex option flags:

  • i — Case-insensitive: /alice/i matches 'Alice', 'ALICE', 'alice'
  • m — Multiline: ^ and $ match the start/end of each line rather than the whole string
  • s — Dot-all: . matches any character including newlines
  • x — Extended: whitespace in the pattern is ignored (for readable patterns with comments)

The most commonly used flag is i. The m flag is useful for searching multi-line text fields like blog content. Multiple flags can be combined: { $options: 'im' }.

// Case-insensitive search for 'javascript'
db.courses.find({ title: { $regex: 'javascript', $options: 'i' } });
// Matches: 'JavaScript', 'JAVASCRIPT', 'javascript', 'JavaScript Tutorial'

// Multiline match: ^ anchors to start of each line
db.articles.find({ content: { $regex: '^Introduction', $options: 'm' } });
// Matches articles where any line starts with 'Introduction'

// Combined flags
db.posts.find({ body: { $regex: 'mongodb', $options: 'si' } });
// Case-insensitive + dot matches newlines in body

Anchors: Starts With and Ends With

Use regex anchors to match the start or end of a string field:

  • ^ anchors to the start: /^Admin/ matches strings that begin with 'Admin'
  • $ anchors to the end: /\.pdf$/ matches strings ending with '.pdf'

A critical performance fact: a prefix regex with a caret (/^prefix/) CAN use a regular B-tree index on that field—MongoDB can seek directly to the prefix in the index. This makes prefix searches much faster than mid-string searches. Never use a leading wildcard (/.*pattern/ or /pattern/ without ^) on a large collection without a text index.

// Prefix match - CAN use index (very efficient)
db.users.find({ username: /^admin/i });
// Matches: 'admin', 'administrator', 'Admin123'
// Uses the index on username (if it exists)

// Suffix match - CANNOT use regular index (slower)
db.files.find({ filename: /\.pdf$/i });
// Matches: 'report.pdf', 'invoice.PDF'
// Must scan all documents - add text index if used frequently

// Mid-string - CANNOT use index
db.products.find({ description: /wireless/i });
// Must scan all documents - use $text index for this

Character Classes and Quantifiers

Regex gives you expressive pattern primitives:

  • . — any character (except newline, unless s flag set)
  • [abc] — character class: matches a, b, or c
  • [a-z] — range: any lowercase letter
  • \d — any digit (equivalent to [0-9])
  • \w — any word character ([a-zA-Z0-9_])
  • *, +, ? — zero or more, one or more, zero or one
  • {n}, {n,m} — exactly n, between n and m occurrences
// Phone number pattern: +1-XXX-XXX-XXXX or similar
db.users.find({ phone: /^\+?\d{1,3}[-. ]?\(?\d{3}\)?[-. ]?\d{3}[-. ]?\d{4}$/ });

// 6-character alphanumeric codes
db.coupons.find({ code: /^[A-Z0-9]{6}$/ });
// Matches: 'SALE99', 'DISC25', 'FREE01'

// Email basic validation
db.users.find({ email: { $regex: '^[\\w.]+@[\\w.]+\\.[a-z]{2,}$', $options: 'i' } });

Regex vs Text Index: Know the Difference

Regex queries and MongoDB's $text operator serve different purposes and have very different performance characteristics:

  • Regex: matches by character pattern. Works on any string field, no special index needed (though prefix anchors use B-tree indexes). Suitable for format validation, prefix search, or pattern matching on small collections or indexed prefix queries.
  • $text / text index: full-text keyword search with tokenization, stemming, and stop-word filtering. Requires a text index. Much faster for keyword search in large text fields (articles, descriptions, comments).

Never use /.*keyword.*/i on a large unindexed collection—it is a full scan and may be slow.

// Use REGEX for: format matching, prefix searches on indexed field
db.orders.find({ orderNumber: /^ORD-2024/ }); // Prefix - can use index

// Use $text for: keyword search in content fields
// First: create a text index
db.articles.createIndex({ content: 'text', title: 'text' });
// Then: full-text search
db.articles.find({ $text: { $search: 'mongodb performance' } });
// Much faster than /mongodb.*performance/i on large collections

ReDoS: The Security Risk

ReDoS (Regular Expression Denial of Service) is an attack where a malicious user crafts an input string that causes a poorly written regex to take exponential time to evaluate. If you pass user input directly into a regex without escaping, an attacker can hang your database query.

Always escape user input before using it in a regex by replacing all special regex characters (. * + ? ^ $ { } ( ) [ ] | \ ) with their escaped equivalents. Many libraries (like escape-string-regexp in Node.js) do this automatically. Additionally, prefer $text for user-facing search inputs over raw regex.

// DANGEROUS: raw user input in regex (ReDoS risk)
const input = req.query.search; // User controls this
db.products.find({ name: { $regex: input } }); // NEVER DO THIS

// SAFE: escape user input before using in regex
function escapeRegex(str) {
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
const safeInput = escapeRegex(req.query.search);
db.products.find({ name: { $regex: safeInput, $options: 'i' } });

// BETTER: Use $text for user-facing search
db.products.find({ $text: { $search: req.query.search } });

Regex on Array Fields

When you apply a regex to an array field, MongoDB checks whether any element of the array matches the pattern—the same containment semantics as equality queries on arrays. This lets you search through arrays of tags, categories, or any string array without a special operator.

For example, a document with tags: ['node.js', 'mongodb', 'backend'] would be returned by { tags: /^mongo/ } because 'mongodb' starts with 'mongo'. The regex is applied to each element independently.

// Document: { tags: ['node.js', 'mongodb', 'backend-dev'] }

// Find products where any tag starts with 'mongo'
db.products.find({ tags: /^mongo/i });
// Returns the document (tags contains 'mongodb')

// Find articles where any category contains 'tech'
db.articles.find({ categories: /tech/i });
// Matches: categories containing 'technology', 'tech-news', 'fintech'

// Index on array field improves regex prefix searches
db.articles.createIndex({ categories: 1 });

Practical Search Example

A typical e-commerce search feature combines regex with other filters to provide a contextual, case-insensitive product search. The query matches product names that contain the search term anywhere in the string, filtered by category and in-stock status.

For small catalogs (under 50,000 products), regex search is acceptable. For larger catalogs or full-description search, Atlas Search (Lucene-based) provides superior relevance ranking, stemming, and performance.

// Search endpoint: GET /products?q=wireless&category=Electronics
app.get('/products', async (req, res) => {
  const filter = { stock: { $gt: 0 } };

  if (req.query.q) {
    const escaped = req.query.q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    filter.name = { $regex: escaped, $options: 'i' };
  }
  if (req.query.category) {
    filter.category = req.query.category;
  }

  const products = await db.collection('products')
    .find(filter)
    .project({ name: 1, price: 1, _id: 1 })
    .limit(50)
    .toArray();

  res.json(products);
});

Regex Performance Summary

Key rules for regex performance in MongoDB:

  • Prefix with ^ (/^prefix/): Can use a B-tree index. Best performance for regex.
  • Case-sensitive prefix (/^prefix/): Fully exploits index ordering.
  • Case-insensitive prefix (/^prefix/i): Partially uses index but still much faster than no anchor.
  • Contains without anchor (/pattern/): Full collection scan—use text index instead.
  • Suffix (/pattern$/): Full collection scan or text index.

When in doubt, test with explain('executionStats') and look for IXSCAN vs COLLSCAN.

// Check if regex query uses an index
db.users.find({ username: /^alice/i })
  .explain('executionStats');
// winningPlan.stage should be 'IXSCAN' if username is indexed

// Compare index scan vs collection scan:
// /^alice/ on indexed field: totalDocsExamined ~= nReturned (efficient)
// /alice/  on any field: totalDocsExamined = all documents (slow!)

Testing Regex Patterns Before Deployment

Before running a regex query on a production collection, test the pattern against sample documents to verify it matches what you intend and does not match what you do not intend. The MongoDB shell lets you test quickly with a small limit(), and JavaScript's String.prototype.test() or regex literals let you validate patterns in Node.js before embedding them in queries.

Also check performance with explain(): a regex that requires a full collection scan should be converted to a text query or have its collection size considered. For new collections, design with search requirements in mind—add text indexes from the start rather than retrofitting them.

// Step 1: Test regex in Node.js before using in query
const pattern = /^wireless/i;
const testStrings = ['Wireless Headphones', 'wireless mouse', 'Wired Keyboard'];
testStrings.forEach(s => console.log(s, '=>', pattern.test(s)));
// 'Wireless Headphones' => true
// 'wireless mouse' => true
// 'Wired Keyboard' => false

// Step 2: Test on production with limit
db.products.find({ name: /^wireless/i }).limit(5);

// Step 3: Check performance
db.products.find({ name: /^wireless/i }).explain('executionStats');

Quick Check

Test your understanding of MongoDB & NoSQL Databases concepts from this lesson.

Lesson Recap

In this lesson you learned: regex queries use /pattern/flags or $regex operator for flexible string pattern matching—the most important flag is i for case-insensitivity, prefix-anchored regexes (/^prefix/) can use B-tree indexes for efficient lookups while mid-string patterns require full scans, and always escape user input before inserting it into a regex to prevent ReDoS attacks—or better yet, use the $text operator with a text index for user-facing search. Next up we move into updating documents with $set, $unset, and other update operators.

자주 묻는 질문

“정규식 쿼리와 패턴 일치” 강의는 무료인가요?

네 — “정규식 쿼리와 패턴 일치” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 MongoDB Academy 강의 전체를 잠금 해제할 수 있습니다. MongoDB Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“정규식 쿼리와 패턴 일치”에서 뭘 배우나요?

문자열 필드에 정규 표현식을 적용하여 유연하게 텍스트 패턴을 검색합니다. 브라우저에서 직접 실행하는 실습 코드로 MongoDB Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

MongoDB Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 MongoDB Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“정규식 쿼리와 패턴 일치” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 MongoDB Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 MongoDB Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 비교 연산자: $eq, $gt, $lt, $in
  2. 논리 연산자: $and, $or, $nor, $not
  3. 요소 연산자와 유형 검사
  4. 정규식 쿼리와 패턴 일치
← MongoDB Academy(으)로 돌아가기