Demo app for Percona Vector Search for MongoDB (mongot). Upload Percona product release notes in Markdown format and search them with:
- Text search — Atlas-compatible
$searchpowered by mongot - Vector search — semantic
$vectorSearchusing embeddings generated by a local Ollama model (nomic-embed-text, 768 dimensions)
Both modes include an AI-generated summary of the most relevant findings (local Ollama chat model), keyword highlighting in results, and a query inspector showing the exact mongosh-ready queries that were executed.
┌──────────────────────┐ nginx :8080 ┌──────────────────────────────────┐
│ Angular 22 (SPA) │ ─────────────► │ Express API (server/) │
│ Search + Upload UI │ /api/* proxied │ POST /api/upload │
└──────────────────────┘ │ POST /api/search (text/vector) │
│ GET /api/documents │
│ POST /api/embeddings/update │
│ GET /api/embeddings/status │
│ GET /api/health │
└────────┬─────────────────────────┘
│
┌──────────────────┼────────────────────┐
│ │ │
┌──────────▼───────┐ ┌───────▼──────┐ ┌─────────▼──────────┐
│ mongod :27017 │ │ mongot │ │ Ollama :11434 │
│ searchIndexMgmt │ │ gRPC :27028 │ │ nomic-embed-text │
└──────────────────┘ │ metrics:9946│ │ llama3.2:1b (chat)│
└──────────────┘ └────────────────────┘
Two compose files are provided — pick the stack you want to run. Both include an Ollama sidecar whose one-shot ollama-init companion pulls nomic-embed-text (~274 MB) and llama3.2:1b (~1.3 GB) on first startup, then warms the chat model into memory so the first search doesn't stall on model load. Models stay loaded indefinitely (OLLAMA_KEEP_ALIVE: -1) — inference runs CPU-only inside Docker, and reloading the chat model from disk would otherwise add ~30–60 s to the first search after every idle period.
One-time setup:
# 1. Password file — mongot requires owner-readable only (0600)
cp pwfile.example pwfile && chmod 600 pwfile
# 2. Keyfile — required by MongoDB for intra-replica-set auth (0400)
openssl rand -base64 756 > keyfile && chmod 400 keyfile# Production / normal run
docker compose -f docker-compose.community.yml up -d --build
# Development — live reload on file changes
docker compose -f docker-compose.community.yml watch| Service | Image | Port |
|---|---|---|
mongod |
mongodb/mongodb-community-server:latest |
27017 |
mongot |
mongodb/mongodb-community-search:latest |
27028 |
ollama |
ollama/ollama:latest |
11434 |
api |
built from server/ |
3000 (internal) |
app |
built from project root | 8080 |
One-time setup (same files as the community stack):
# 1. Password file — mongot requires owner-readable only (0600)
cp pwfile.example pwfile && chmod 600 pwfile
# 2. Keyfile — required by MongoDB for intra-replica-set auth (0400)
openssl rand -base64 756 > keyfile && chmod 400 keyfile# Production / normal run
docker compose -f docker-compose.percona.yml up -d --build
# Development — live reload on file changes
docker compose -f docker-compose.percona.yml watch| Service | Image | Port |
|---|---|---|
mongod |
perconalab/percona-server-mongodb:8.3.0-1 |
27017 |
mongot |
perconalab/percona-server-mongodb-mongot:0.50.0 |
27028 (gRPC), 9946 (metrics) |
search-init |
perconalab/percona-server-mongodb:8.3.0-1 |
— (one-shot) |
ollama |
ollama/ollama:latest |
11434 |
api |
built from server/ |
3000 |
app |
built from project root | 8080 |
On first run the mongod entrypoint bootstraps the replica set and creates the root and mongotUser users, then the one-shot search-init service creates the two search indexes the API expects (default and vector_index) — no manual index setup is needed. It is idempotent, so re-running the stack is safe.
http://localhost:8080
docker compose watch keeps the stack running and reacts to file changes automatically:
| Service | Trigger | Action |
|---|---|---|
api |
server/src/** |
sync+restart — files are copied into the container; the server restarts without rebuilding the image |
api |
server/package.json |
rebuild — reinstalls dependencies and rebuilds the image |
app |
src/**, public/**, angular.json, package.json |
rebuild — Angular is compiled ahead-of-time, so a full image rebuild is required |
docker compose -f docker-compose.community.yml watchThe api sync+restart cycle is near-instant. The app rebuild takes ~30–60 s depending on machine speed (Angular AOT compile + nginx image layer).
# Tail logs for all services
docker compose -f docker-compose.community.yml logs -f
# Tail logs for a single service
docker compose -f docker-compose.community.yml logs -f api
# Check Ollama model status
docker exec ollama-community ollama list
# Stop and remove containers (keeps volumes)
docker compose -f docker-compose.community.yml down
# Stop and remove containers AND volumes (full reset)
docker compose -f docker-compose.community.yml down -v
# Open a mongosh session against the community stack
docker exec -it mongod-community \
mongosh -u root -p password --authenticationDatabase admin502 Bad Gateway after recreating the
apicontainer? nginx in theappcontainer resolves theapihostname once at startup, so a recreated API container with a new IP leaves nginx pointing at the old one. Fix withdocker restart percona-rn-search-app-percona(or…-community).
Percona stack: skip this section — the
search-initservice creates both indexes automatically (seeinit-search-indexes-percona.sh).
For the community stack (or any manual setup), run these once after the stack is up — mongot needs index definitions before $search and $vectorSearch queries work. Without them, search queries succeed but return zero results (mongot logs No index in catalog).
Text search index:
use release_notes
db.documents.createSearchIndex("default", { mappings: { dynamic: true } })Dynamic mapping covers every field the API searches (content, releaseHighlights.title, releaseHighlights.content, newFeatures.description, improvements.description, bugFixes.description).
Vector search index (required for semantic search):
db.documents.createSearchIndex(
"vector_index",
"vectorSearch",
{
fields: [
{
type: "vector",
path: "embedding",
numDimensions: 768,
similarity: "cosine",
},
{
type: "filter",
path: "product",
},
]
}
)Note: if an index does not exist, mongot returns an empty result set rather than an error — so
$search/$vectorSearchappear to "work" but find nothing. If the$searchquery itself fails (e.g. mongot is down), the API falls back to a$textindex lookup and then to a regex scan. For vector search, also make sure embeddings have been generated (see below).
Install Ollama and pull the required models:
ollama pull nomic-embed-text # embeddings (vector search)
ollama pull llama3.2:1b # chat model (AI summary + keyword extraction)Any other chat model already on your Ollama instance works too — set OLLAMA_CHAT_MODEL in server/.env to override the default. The Docker stacks use llama3.2:1b because inference is CPU-only inside Docker; running Ollama natively (with GPU acceleration) makes larger models like llama3.2 (3B) practical, with better keyword extraction quality.
cd server
cp .env.example .env # set MONGODB_URI and OLLAMA_URL
npm install
npm run dev # http://localhost:3000Environment variables:
| Variable | Default | Description |
|---|---|---|
MONGODB_URI |
(required) | mongodb://… URI for Percona Server for MongoDB |
MONGODB_DB |
release_notes |
Database name |
MONGODB_COLLECTION |
documents |
Collection name |
PORT |
3000 |
HTTP port |
OLLAMA_URL |
http://localhost:11434 |
Ollama base URL |
OLLAMA_EMBED_MODEL |
nomic-embed-text |
Ollama model used for generating embeddings |
OLLAMA_CHAT_MODEL |
llama3.2 |
Ollama chat model used for AI summaries and keyword extraction (the Docker stacks set llama3.2:1b) |
npm install
npm start # http://localhost:4200Node.js ≥ 24.15.0 is required by Angular CLI 22.
The dev server proxies /api/* to http://localhost:3000 automatically via the environment.development.ts apiUrl.
Go to /upload, drag & drop one or more .md release notes files.
Filename convention: <version>.md (e.g. 7.0.18-11.md).
The product name is auto-detected from the H1 heading.
Embeddings are generated automatically at upload time if Ollama is reachable.
After uploading documents (or if Ollama was unavailable during upload), go to /upload and use the Embeddings panel:
- Update missing — generates embeddings only for documents that don't have one yet
- Regenerate all — re-embeds every document (useful after switching models)
The panel shows how many documents currently have embeddings vs. the total, and whether Ollama is reachable.
Go to /search and type a natural language query. Use the Text / Vector toggle to choose the search mode:
| Mode | Powered by | When to use |
|---|---|---|
| Text | mongot $search |
Keyword and fuzzy matching |
| Vector | mongot $vectorSearch + Ollama |
Semantic / conceptual queries |
After a search (text or vector), an AI Summary panel appears above the result cards. The local Ollama chat model (llama3.2:1b in the Docker stacks) reads the top matching release notes and writes a short, conversational answer that highlights the findings most relevant to your query. The summary is generated entirely on-device — no data leaves your machine. If Ollama is unavailable or times out, the panel shows the reason instead.
Expect ~15–20 s per search in the Docker stacks: the summary and keyword extraction run on CPU. The nginx proxy allows up to 180 s (proxy_read_timeout in nginx.conf) before giving up on the API.
Matched terms are highlighted in the result cards. Keywords are extracted from your query by the Ollama chat model, which also expands common Percona abbreviations (e.g. PSMDB → Percona Server for MongoDB, PBM → Percona Backup for MongoDB) so both forms light up.
Each search response includes the exact queries that were executed ($search / $vectorSearch aggregations, plus any fallbacks). Expand the MongoDB queries panel under the search box to copy them as mongosh-ready snippets for verification or troubleshooting.
The header shows a live status indicator for the backend API (polled via GET /api/health), so you can tell at a glance whether the stack is up.
Example queries:
- "bug fix to LDAP"
- "Google Workload Federation"
- "audit log improvements in 7.0"
- "performance regression in replication" ← vector search shines here
Filter by product using the dropdown. Results show a relevance score and are ranked by it.
- Percona Server for MongoDB
- Percona Backup for MongoDB
- Percona Operator for MongoDB
- Percona ClusterSync for MongoDB