MongoDB Academy · Oppitunti

Regex-kyselyt ja hahmonsovitus

Käytätte säännöllisiä lausekkeita merkkijonokenttien joustavaan tekstihakuun ja hahmojen täsmäyttämiseen.

Oppitunti 4/413 vaihetta

Regex-kyselyt ja hahmonsovitus on ilmainen MongoDB Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu MongoDB Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. MongoDB Academy-kurssilla on yhteensä 4 oppituntia.

Milloin hahmonsovitusta tarvitaan

Joskus dokumentteja on haettava merkkijonokentästä, joka sisältää, alkaa tai päättyy tiettyyn hahmoon, mutta tarkkaa arvoa ei tiedetä. Yksinkertaiset yhtäsuuruussuodattimet, kuten { name: 'Alice' }, löytävät vain täsmälleen vastaavat merkkijonot. Säännölliset lausekkeet (regex) mahdollistavat joustavan hahmonsovituksen MongoDB:n merkkijonokenttiä vasten.

MongoDB tukee regexiä $regex-operaattorin avulla tai välittämällä JavaScriptin regex-literaalin suoraan kyselysuodattimeen. Molemmat tavat toimivat, mutta niiden syntaksi on hieman erilainen esimerkiksi kirjainkoon huomioimattomuutta määritettäessä.

Regex-syntaksin perusteet MongoDB:ssä

Regexiä voi käyttää MongoDB-kyselyissä kahdella tavalla:

  • JS-regex-literaali: { name: /alice/i } — tiivis muoto, jossa liput kirjoitetaan sulkevan kauttaviivan jälkeen
  • $regex-operaattori: { name: { $regex: 'alice', $options: 'i' } } — monisanaisempi muoto, jota tarvitaan, kun se yhdistetään muihin operaattoreihin

Molemmat muodot tuottavat samat tulokset. Käyttäkää JS-literaalisyntaksia yksinkertaisissa kyselyissä. Käyttäkää $regex-operaattoria, kun hahmo on muodostettava dynaamisesti merkkijonomuuttujasta tai kun se on yhdistettävä saman kentän muihin operaattoreihin.

// 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-asetukset: i, m, s, x

MongoDB tukee neljää regex-asetuslippua:

  • i — kirjainkoolla ei ole merkitystä: /alice/i vastaa arvoja 'Alice', 'ALICE' ja 'alice'
  • m — monirivisyys: ^ ja $ vastaavat kunkin rivin alkua ja loppua koko merkkijonon sijaan
  • s — piste vastaa kaikkea: . vastaa mitä tahansa merkkiä, myös rivinvaihtoja
  • x — laajennettu muoto: hahmon välilyönnit ohitetaan (luettavia, kommentoituja hahmoja varten)

Yleisimmin käytetty lippu on i. m-lippu on hyödyllinen monirivisen tekstin, kuten blogisisällön, haussa. Useita lippuja voi yhdistää: { $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

Ankkurit: merkkijonon alku ja loppu

Regex-ankkureilla voit täsmäyttää merkkijonokentän alun tai lopun:

  • ^ ankkuroi alkuun: /^Admin/ vastaa merkkijonoja, jotka alkavat tekstillä 'Admin'
  • $ ankkuroi loppuun: /\.pdf$/ vastaa merkkijonoja, jotka päättyvät tekstiin '.pdf'

Tärkeä suorituskykyyn liittyvä tieto: hattumerkillä ankkuroitu prefiksiregex (/^prefix/) VOI käyttää kentän tavallista B-tree-indeksiä – MongoDB voi siirtyä indeksissä suoraan prefiksin kohdalle. Siksi prefiksihaku on paljon nopeampi kuin merkkijonon keskeltä tehtävä haku. Älkää koskaan käyttäkö alussa jokerimerkkiä (/.*pattern/ tai /pattern/ ilman merkkiä ^) suuressa kokoelmassa ilman tekstihakemistoa.

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

Merkkiluokat ja toistomääreet

Regex tarjoaa ilmaisukykyisiä hahmon peruselementtejä:

  • . — mikä tahansa merkki (paitsi rivinvaihto, ellei s-lippua ole asetettu)
  • [abc] — merkkiluokka: vastaa merkkiä a, b tai c
  • [a-z] — väli: mikä tahansa pieni kirjain
  • \d — mikä tahansa numero (vastaa merkintää [0-9])
  • \w — mikä tahansa sanamerkki ([a-zA-Z0-9_])
  • *, +, ? — nolla tai useampi, yksi tai useampi, nolla tai yksi
  • {n}, {n,m} — täsmälleen n esiintymää, n–m esiintymää
// 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 ja tekstihakemisto: tunnistakaa ero

Regex-kyselyt ja MongoDB:n $text-operaattori palvelevat eri tarkoituksia, ja niiden suorituskykyominaisuudet poikkeavat huomattavasti:

  • Regex: täsmäyttää merkkihahmon perusteella. Toimii kaikissa merkkijonokentissä eikä vaadi erityistä indeksiä (vaikka prefiksiankkurit käyttävät B-tree-indeksejä). Sopii muodon tarkistamiseen, prefiksihakuun sekä hahmonsovitukseen pienissä kokoelmissa tai indeksoiduissa prefiksikyselyissä.
  • $text / tekstihakemisto: kokotekstihaku, joka käyttää tokenisointia, vartalointia ja stop-sanojen suodatusta. Vaatii tekstihakemiston. On paljon nopeampi suurten tekstikenttien (artikkelit, kuvaukset, kommentit) avainsanahaussa.

Älkää koskaan käyttäkö ilmaisua /.*keyword.*/i suuressa indeksoimattomassa kokoelmassa – se käy koko kokoelman läpi ja voi olla hidas.

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

ReDoS (Regular Expression Denial of Service) on hyökkäys, jossa pahantahtoinen käyttäjä muodostaa syötemerkkijonon, jonka vuoksi huonosti kirjoitetun regexin suorittaminen vie eksponentiaalisesti aikaa. Jos käyttäjän syöte välitetään suoraan regexiin ilman escapointia, hyökkääjä voi jumittaa tietokantakyselyn.

Tehkää käyttäjän syötteelle aina escape-käsittely ennen sen käyttöä regexissä korvaamalla kaikki regexin erikoismerkit (. * + ? ^ $ { } ( ) [ ] | \ ) escapatuilla vastineillaan. Monet kirjastot, kuten Noden.js:n escape-string-regexp, tekevät tämän automaattisesti. Suosikaa lisäksi käyttäjille tarkoitetuissa hakukentissä $text-operaattoria suoran regexin sijaan.

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

Kun käytätte regexiä taulukkokenttään, MongoDB tarkistaa, vastaako jokin taulukon alkio hahmoa – semantiikka on sama kuin taulukkojen yhtäsuuruuskyselyissä. Näin voitte hakea tunnisteiden, luokkien tai minkä tahansa merkkijonotaulukon sisältä ilman erityistä operaattoria.

Esimerkiksi dokumentti, jonka sisältö on tags: ['node.js', 'mongodb', 'backend'], palautetaan kyselyllä { tags: /^mongo/ }, koska 'mongodb' alkaa tekstillä 'mongo'. Regex kohdistetaan kuhunkin alkioon erikseen.

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

Käytännön hakuesimerkki

Tyypillisessä verkkokaupan hakutoiminnossa regex yhdistetään muihin suodattimiin kontekstuaalisen ja kirjainkoosta riippumattoman tuotehaun tarjoamiseksi. Kysely etsii tuotteen nimen sisältä hakutermiä mistä tahansa kohdasta ja suodattaa tulokset luokan sekä varastotilanteen perusteella.

Pienissä tuoteluetteloissa (alle 50 000 tuotetta) regex-haku on hyväksyttävä. Suuremmissa luetteloissa tai koko kuvauksen kattavassa haussa Atlas Search (Lucene-pohjainen) tarjoaa paremman relevanssijärjestyksen, vartaloinnin ja suorituskyvyn.

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

Regexin suorituskyvyn yhteenveto

MongoDB:n regex-suorituskyvyn tärkeimmät säännöt:

  • Alkuun merkki ^ (/^prefix/): voi käyttää B-tree-indeksiä. Regexin paras suorituskyky.
  • Kirjainkoolla erotteleva prefiksi (/^prefix/): hyödyntää indeksin järjestystä täysin.
  • Kirjainkoosta riippumaton prefiksi (/^prefix/i): käyttää indeksiä osittain, mutta on silti paljon nopeampi kuin ankkuroimaton haku.
  • Ankkuroimaton sisältöhaku (/pattern/): käy koko kokoelman läpi – käyttäkää sen sijaan tekstihakemistoa.
  • Loppuun kohdistuva haku (/pattern$/): käy koko kokoelman läpi tai käyttää tekstihakemistoa.

Jos olette epävarmoja, testatkaa kyselyllä explain('executionStats') ja tarkistakaa, käytetäänkö vaihetta IXSCAN vai 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!)

Regex-kuvioiden testaaminen ennen käyttöönottoa

Testatkaa regex-kuvio tuotantokokoelmassa ennen kyselyn suorittamista esimerkkidokumentteja vasten varmistaaksenne, että se vastaa tarkoitettuja merkkijonoja eikä vastaa ei-toivottuja merkkijonoja. MongoDB:n shellissä voitte testata kuviota nopeasti pienellä limit()-arvolla, ja JavaScriptin String.prototype.test() tai regex-literaalit mahdollistavat kuvioiden tarkistamisen Nodessa ennen niiden liittämistä kyselyihin.

Tarkistakaa suorituskyky myös komennolla explain(): koko kokoelman läpikäyntiä edellyttävä regex kannattaa muuttaa tekstikyselyksi tai kokoelman koko on otettava huomioon. Suunnitelkaa uudet kokoelmat hakuvaatimukset huomioiden – lisätkää tekstihakemistot alusta alkaen sen sijaan, että lisäätte ne jälkikäteen.

// 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');

Pikatarkistus

Testatkaa, miten hyvin ymmärrätte tällä oppitunnilla käsitellyt MongoDB:n ja NoSQL-tietokantojen käsitteet.

Oppitunnin yhteenveto

Tällä oppitunnilla opitte seuraavaa: regex-kyselyissä käytetään muotoa /pattern/flags tai $regex-operaattoria joustavaan merkkijonojen hahmonsovitukseen – tärkein lippu on i, joka tekee hausta kirjainkoosta riippumattoman; prefiksiin ankkuroitu regex (/^prefix/) voi käyttää B-tree-indeksejä tehokkaaseen hakuun, kun taas merkkijonon keskelle kohdistuvat hahmot vaativat koko kokoelman läpikäynnin; ja käyttäjän syöte on aina escapattava ennen sen lisäämistä regexiin ReDoS-hyökkäysten estämiseksi – tai vielä parempi, käyttäkää käyttäjille suunnatussa haussa $text-operaattoria tekstihakemiston kanssa. Seuraavaksi siirrymme dokumenttien päivittämiseen $set-, $unset- ja muilla päivitysoperaattoreilla.

Aloita maksutta

Opi JavaScript tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
30
Oppitunnit
120

Usein kysytyt kysymykset

Onko oppitunti ”Regex-kyselyt ja hahmonsovitus” ilmainen?

Kyllä – oppitunnin ”Regex-kyselyt ja hahmonsovitus” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko MongoDB Academy-kurssin, päivitä CoddyKit PROhon. MongoDB Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Regex-kyselyt ja hahmonsovitus”?

Käytätte säännöllisiä lausekkeita merkkijonokenttien joustavaan tekstihakuun ja hahmojen täsmäyttämiseen. Harjoittelet MongoDB Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni MongoDB Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin MongoDB Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.

Kuinka kauan ”Regex-kyselyt ja hahmonsovitus”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä MongoDB Academy-oppitunnilla?

Kyllä. Jokainen MongoDB Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Vertailuoperaattorit: $eq, $gt, $lt, $in
  2. Loogiset operaattorit: $and, $or, $nor, $not
  3. Elementtioperaattorit ja tyyppitarkistukset
  4. Regex-kyselyt ja hahmonsovitus
← Takaisin: MongoDB Academy