Syncing a database
Import your existing rows once, then keep the index up to date on every insert, update and delete.
Your database stays the source of truth, and ZeroIndex holds a copy of the fields you want to search. This guide uses Postgres and Node.js, but the pattern works with any database: one full import, then small updates as rows change.
Choose the fields
Only send what people search, filter, sort or see in results. Leaving out large text fields keeps the index small and fast.
const toDocument = (row) => ({
id: row.id,
name: row.name,
brand: row.brand,
category: row.category,
price: Number(row.price),
in_stock: row.stock > 0,
updated_at: Math.floor(row.updated_at.getTime() / 1000),
});Import everything once
Read the table in pages and send each page as a batch.
import pg from "pg";
import { ZeroIndex } from "@zeroindex/client";
const db = new pg.Pool();
const index = new ZeroIndex(process.env.ZEROINDEX_KEY).index("products");
let lastId = 0;
while (true) {
const { rows } = await db.query(
"select * from products where id > $1 order by id limit 1000",
[lastId],
);
if (rows.length === 0) break;
await index.addDocuments(rows.map(toDocument));
lastId = rows.at(-1).id;
}Send changes as they happen
Update the index wherever your app writes to the table. Send the document after the database transaction commits, so a rollback never leaves the index ahead of the database.
export async function saveProduct(product) {
const row = await db.query("update products set ... returning *", [...]);
await index.updateDocuments([toDocument(row.rows[0])]);
}
export async function removeProduct(id) {
await db.query("delete from products where id = $1", [id]);
await index.deleteDocument(id);
}Catch anything you missed
Run a small job every few minutes that sends rows changed since the last run. It covers writes made outside your app, like a migration or a manual fix.
const { rows } = await db.query("select * from products where updated_at > $1", [lastRun]);
if (rows.length > 0) await index.updateDocuments(rows.map(toDocument));Rebuilding without downtime
To change your document shape or settings from scratch, import into a new index such as products_new, then swap it with the live one. Searches move over in one step, with no empty results in between.
await client.swapIndexes([{ indexes: ["products", "products_new"] }]);