Quick Tutorial
In this tutorial you'll build a small knowledge base — push a batch of articles, search by meaning, filter by field value, link articles to their authors, and wrap multi-step writes in a transaction.
Every concept introduced here applies equally to agent memory, product catalogs, document stores, or any other data shape you throw at RushDB.
Prerequisites
- A RushDB account and API token — see Get API Key
- TypeScript/JavaScript, Python, or any HTTP client
Step 1: Initialize
- Python
- TypeScript
- shell
from rushdb import RushDB
db = RushDB("RUSHDB_API_KEY")
import RushDB from '@rushdb/javascript-sdk';
const db = new RushDB('RUSHDB_API_KEY');
export RUSHDB_API_KEY="your-api-key"
Step 2: Push Records
Use importJson to push a batch of articles in one call. RushDB infers field types automatically and returns record instances you can use immediately.
- Python
- TypeScript
- shell
articles = db.records.create_many(
label="ARTICLE",
data=[
{
"title": "Getting started with graph databases",
"content": "Graph databases model data as nodes and edges, making relationship queries fast and intuitive.",
"tags": ["databases", "graphs"],
"author": "alice"
},
{
"title": "Vector search explained",
"content": "Vector embeddings let you search by semantic meaning rather than exact keywords.",
"tags": ["ai", "search"],
"author": "bob"
},
{
"title": "Building AI agents with persistent memory",
"content": "Agents that remember past interactions can reason across sessions and personalize responses.",
"tags": ["ai", "agents"],
"author": "alice"
}
],
options={ "returnResult": True }
)
const { data: articles } = await db.records.importJson({
label: 'ARTICLE',
data: [
{
title: 'Getting started with graph databases',
content: 'Graph databases model data as nodes and edges, making relationship queries fast and intuitive.',
tags: ['databases', 'graphs'],
author: 'alice'
},
{
title: 'Vector search explained',
content: 'Vector embeddings let you search by semantic meaning rather than exact keywords.',
tags: ['ai', 'search'],
author: 'bob'
},
{
title: 'Building AI agents with persistent memory',
content: 'Agents that remember past interactions can reason across sessions and personalize responses.',
tags: ['ai', 'agents'],
author: 'alice'
}
],
options: { returnResult: true }
})
curl -X POST "https://api.rushdb.com/api/v1/records/import/json" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"label": "ARTICLE",
"data": [
{
"title": "Getting started with graph databases",
"content": "Graph databases model data as nodes and edges, making relationship queries fast and intuitive.",
"tags": ["databases", "graphs"],
"author": "alice"
},
{
"title": "Vector search explained",
"content": "Vector embeddings let you search by semantic meaning rather than exact keywords.",
"tags": ["ai", "search"],
"author": "bob"
},
{
"title": "Building AI agents with persistent memory",
"content": "Agents that remember past interactions can reason across sessions and personalize responses.",
"tags": ["ai", "agents"],
"author": "alice"
}
]
}'
Swap label: 'ARTICLE' for label: 'MEMORY' and push conversation snippets, tool results, or any structured context. The rest of the tutorial — semantic search, filters, relationships — applies unchanged.
Step 3: Semantic Search
Create an embedding index on the content field, wait for backfill to complete, then search by meaning.
- Python
- TypeScript
- shell
import time
# Create the embedding index
index = db.ai.indexes.create({
"label": "ARTICLE",
"propertyName": "content"
}).data
# Poll until all records are indexed
stats = db.ai.indexes.stats(index["id"]).data
while stats["indexedRecords"] < stats["totalRecords"]:
time.sleep(0.5)
stats = db.ai.indexes.stats(index["id"]).data
# Search by meaning
results = db.ai.search({
"propertyName": "content",
"query": "how do agents remember things across conversations",
"labels": ["ARTICLE"],
"limit": 3
}).data
for result in results:
print(f"[{result['__score']:.3f}] {result['title']}")
# [0.891] Building AI agents with persistent memory
# [0.743] Vector search explained
# [0.612] Getting started with graph databases
// Create the embedding index — backfill starts immediately
const { data: index } = await db.ai.indexes.create({
label: 'ARTICLE',
propertyName: 'content'
})
// Poll until all records are indexed
let stats = await db.ai.indexes.stats(index.id)
while (stats.data.indexedRecords < stats.data.totalRecords) {
await new Promise(r => setTimeout(r, 500))
stats = await db.ai.indexes.stats(index.id)
}
// Search by meaning — returns results sorted by cosine similarity
const { data: results } = await db.ai.search({
propertyName: 'content',
query: 'how do agents remember things across conversations',
labels: ['ARTICLE'],
limit: 3
})
for (const result of results) {
console.log(`[${result.__score.toFixed(3)}] ${result.title}`)
}
// [0.891] Building AI agents with persistent memory
// [0.743] Vector search explained
// [0.612] Getting started with graph databases
# Create the embedding index
INDEX_ID=$(curl -s -X POST "https://api.rushdb.com/api/v1/ai/indexes" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"label": "ARTICLE", "propertyName": "content"}' \
| jq -r '.data.id')
# Check stats — wait until indexedRecords == totalRecords
curl "https://api.rushdb.com/api/v1/ai/indexes/$INDEX_ID/stats" \
-H "Authorization: Bearer $RUSHDB_API_KEY"
# Search by meaning
curl -X POST "https://api.rushdb.com/api/v1/ai/search" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"propertyName": "content",
"query": "how do agents remember things across conversations",
"labels": ["ARTICLE"],
"limit": 3
}'
Each result includes a __score field (0–1) — cosine similarity between the query embedding and the record's content embedding. Higher is more relevant.
Step 4: Structured Query
Use records.find to filter by exact field values. This is independent of the embedding index.
- Python
- TypeScript
- shell
ai_articles = db.records.find({
"labels": ["ARTICLE"],
"where": {
"tags": { "$in": ["ai"] }
}
})
print([a.data["title"] for a in ai_articles])
# ['Vector search explained', 'Building AI agents with persistent memory']
const aiArticles = await db.records.find({
labels: ['ARTICLE'],
where: {
tags: { $in: ['ai'] }
}
})
console.log(aiArticles.map(a => a.data.title))
// ['Vector search explained', 'Building AI agents with persistent memory']
curl -X POST "https://api.rushdb.com/api/v1/records/search" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"labels": ["ARTICLE"],
"where": {
"tags": { "$in": ["ai"] }
}
}'
See the Where clause reference for the full list of operators ($gt, $lt, $contains, $not, and more).
Step 5: Semantic Search with Filter
Combine a where filter with db.ai.search to scope semantic search to a subset of records. RushDB narrows candidates by field values first, then ranks them by cosine similarity.
- Python
- TypeScript
- shell
# Only search within AI-tagged articles
filtered = db.ai.search({
"propertyName": "content",
"query": "memory and learning",
"labels": ["ARTICLE"],
"where": {
"tags": { "$in": ["ai"] }
},
"limit": 5
}).data
for result in filtered:
print(f"[{result['__score']:.3f}] {result['title']}")
// Only search within AI-tagged articles
const { data: filtered } = await db.ai.search({
propertyName: 'content',
query: 'memory and learning',
labels: ['ARTICLE'],
where: {
tags: { $in: ['ai'] }
},
limit: 5
})
for (const result of filtered) {
console.log(`[${result.__score.toFixed(3)}] ${result.title}`)
}
curl -X POST "https://api.rushdb.com/api/v1/ai/search" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"propertyName": "content",
"query": "memory and learning",
"labels": ["ARTICLE"],
"where": {
"tags": { "$in": ["ai"] }
},
"limit": 5
}'
Without a where clause, RushDB still performs exact semantic ranking over the label-scoped candidates. Adding where reduces the candidate set first, which can improve latency on larger datasets.
Step 6: Relationships
Link each article to an author record. Relationships are first-class in RushDB — they have a type, a direction, and can carry their own properties.
- Python
- TypeScript
- shell
# Create an author record
author = db.records.create(
label="AUTHOR",
data={"name": "Alice", "email": "alice@example.com"}
)
# Attach alice's articles to the author
for article in [a for a in articles if a.data.get("author") == "alice"]:
article.attach(
target=author,
options={"type": "WRITTEN_BY", "direction": "out"}
)
// Create an author record
const author = await db.records.create({
label: 'AUTHOR',
data: { name: 'Alice', email: 'alice@example.com' }
})
// Attach alice's articles to the author
for (const article of articles.filter(a => a.data.author === 'alice')) {
await article.attach({
target: author,
options: { type: 'WRITTEN_BY' }
})
}
# Create an author record — save the returned __id
AUTHOR_ID=$(curl -s -X POST "https://api.rushdb.com/api/v1/records" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"label": "AUTHOR",
"data": {"name": "Alice", "email": "alice@example.com"}
}' | jq -r '.data.__id')
# Attach an article to the author (replace ARTICLE_ID with the actual ID)
curl -X POST "https://api.rushdb.com/api/v1/relationships/$ARTICLE_ID" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"targetIds": ["'"$AUTHOR_ID"'"],
"type": "WRITTEN_BY"
}'
Step 7: Transactions (Optional)
Wrap multiple writes in a transaction to guarantee all-or-nothing atomicity.
- Python
- TypeScript
- shell
with db.tx.begin() as tx:
new_article = db.records.create(
label="ARTICLE",
data={
"title": "Transactions made simple",
"content": "ACID guarantees ensure your data stays consistent even when things fail.",
"tags": ["databases"],
"author": "bob"
},
transaction=tx
)
new_article.attach(
target=author,
options={"type": "WRITTEN_BY", "direction": "out"},
transaction=tx
)
# Commits automatically on exit; rolls back on exception
const tx = await db.tx.begin()
try {
const newArticle = await db.records.create({
label: 'ARTICLE',
data: {
title: 'Transactions made simple',
content: 'ACID guarantees ensure your data stays consistent even when things fail.',
tags: ['databases'],
author: 'bob'
},
transaction: tx
})
await newArticle.attach({
target: author,
options: { type: 'WRITTEN_BY' },
transaction: tx
})
await tx.commit()
console.log('Article created and linked — committed.')
} catch (err) {
await tx.rollback()
console.error('Rolled back:', err)
}
# Begin transaction
TX_ID=$(curl -s -X POST "https://api.rushdb.com/api/v1/transactions" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
| jq -r '.id')
# Create article within transaction
NEW_ARTICLE_ID=$(curl -s -X POST "https://api.rushdb.com/api/v1/records" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Transaction-ID: $TX_ID" \
-d '{
"label": "ARTICLE",
"data": {
"title": "Transactions made simple",
"content": "ACID guarantees ensure your data stays consistent even when things fail.",
"tags": ["databases"],
"author": "bob"
}
}' | jq -r '.data.__id')
# Attach to author within same transaction
curl -X POST "https://api.rushdb.com/api/v1/relationships/$NEW_ARTICLE_ID" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Transaction-ID: $TX_ID" \
-d '{
"targetIds": ["'"$AUTHOR_ID"'"],
"type": "WRITTEN_BY"
}'
# Commit
curl -X POST "https://api.rushdb.com/api/v1/transactions/$TX_ID/commit" \
-H "Authorization: Bearer $RUSHDB_API_KEY"
Next Steps
- Records — data model and field types
- Labels — organizing records by category
- Relationships — connecting records into a graph
- Search & Querying — where clauses, ordering, pagination
- Transactions — atomicity and consistency
- TypeScript SDK
- Python SDK
- REST API