Embeddings 101: Semantic Search in MongoDB
Keyword search has a fatal flaw: it matches characters, not meaning. A user searching "laptop won't turn on" never finds the article titled "resolving boot failures" because they share no words. Embeddings fix that by representing meaning as geometry — and with MongoDB now able to store and search vectors, semantic search drops into a MERN stack without a second database.
Meaning, not keywords
An embedding model maps text to a vector such that related ideas land near each other in space. Search stops being "which documents contain these exact tokens" and becomes "which documents mean something close to this." That is the difference between a search that frustrates users and one that feels like it understood them.
Generate, store, search
The workflow is three moves. When a document is created or updated, embed its text and store the vector alongside it. At query time, embed the search string the same way and run a nearest-neighbour search over the stored vectors. Because the embedding lives on the document, your data and its semantic index never drift apart.
// store the vector beside the document
await Docs.insertOne({ ...doc, embedding: await embed(doc.text) });
// query by meaning, return the closest matches
const results = await Docs.aggregate([
{ $vectorSearch: {
index: "embedding_index",
path: "embedding",
queryVector: await embed(searchText),
numCandidates: 150,
limit: 8,
} },
]);The details that decide quality
Two choices shape results more than anything else: keep your embedding model consistent — vectors from different models are not comparable — and re-embed when a document's text changes, or your index quietly rots. Get those right and semantic search is shockingly good with very little code.
Keyword search finds the words the user typed. Semantic search finds the thing they meant. Only one of those is what they actually wanted.
For the mental model behind the vectors, start with vector databases for MERN developers.