Find & Query
RushDB provides four read methods: look up by ID, find one, find unique, or run a full search query with filtering, aggregation, and relationship traversal — all through a unified SearchQuery object.
Find by ID
- Python
- TypeScript
- shell
db.records.find_by_id()
# Single record
movie = db.records.find_by_id("movie-123")
# Multiple records
movies = db.records.find_by_id(["movie-123", "movie-456"])
db.records.findById()
const movie = await db.records.findById('movie-id-123')
const movies = await db.records.findById(['id-1', 'id-2', 'id-3'])
Returns DBRecordInstance (single) or DBRecordsArrayInstance (array).
GET /api/v1/records/:entityId
curl https://api.rushdb.com/api/v1/records/movie-123 \
-H "Authorization: Bearer $RUSHDB_API_KEY"
Find One
Returns the first matching record, or null / None if none found.
- Python
- TypeScript
- shell
db.records.find_one()
movie = db.records.find_one({
"labels": ["MOVIE"],
"where": {"title": "Inception"}
})
db.records.findOne()
const movie = await db.records.findOne({
labels: ['MOVIE'],
where: { title: 'Inception' }
})
Use POST /api/v1/records/search with "limit": 1.
curl -X POST https://api.rushdb.com/api/v1/records/search \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"labels": ["MOVIE"], "where": {"title": "Inception"}, "limit": 1}'
Find Unique
Like find_one / findOne, but throws NonUniqueResultError if more than one record matches.
- Python
- TypeScript
- shell
db.records.find_uniq()
movie = db.records.find_uniq({
"labels": ["MOVIE"],
"where": {"title": "Inception"}
})
db.records.findUniq()
import { NonUniqueResultError } from '@rushdb/javascript-sdk'
try {
const movie = await db.records.findUniq({
labels: ['MOVIE'],
where: { title: 'Inception' }
})
} catch (e) {
if (e instanceof NonUniqueResultError) console.error(`found ${e.count} matches`)
}
Not a dedicated endpoint — check total from a search response to verify uniqueness.
Search Records
Full search with filtering, sorting, and pagination.
- Python
- TypeScript
- shell
db.records.find()
result = db.records.find({
"labels": ["MOVIE"],
"where": {"rating": {"$gte": 8}, "genre": "sci-fi"},
"orderBy": {"rating": "desc"},
"limit": 20,
"skip": 0
})
for movie in result:
print(movie.get("title"), movie.get("rating"))
print(f"{len(result)} shown, {result.total} total")
db.records.find()
const { data: movies, total } = await db.records.find({
labels: ['MOVIE'],
where: { rating: { $gte: 8 }, genre: 'sci-fi' },
orderBy: { rating: 'desc' },
limit: 20,
skip: 0
})
POST /api/v1/records/search
curl -X POST https://api.rushdb.com/api/v1/records/search \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"labels": ["MOVIE"],
"where": {"rating": {"$gte": 8}, "genre": "sci-fi"},
"orderBy": {"rating": "desc"},
"limit": 20,
"skip": 0
}'
SearchQuery parameters
| Field | Type | Description |
|---|---|---|
labels | string[] | Filter by one or more labels |
where | object | Field conditions and operators (see Where Operators) |
orderBy | string | object | Sort criteria (see Pagination & Order) |
limit | number | Max records to return (default: 1000). Omit when using select |
skip | number | Records to skip for pagination |
select | object | Output-shaping expressions (see Select Expressions) |
groupBy | string[] | Grouping keys, e.g. ['$record.genre'] |
Where Operators
# Numeric comparisons
{"rating": {"$gt": 7, "$lt": 10}}
{"rating": {"$gte": 8, "$lte": 9.5}}
# Set membership
{"genre": {"$in": ["sci-fi", "thriller"]}}
{"genre": {"$nin": ["romance"]}}
# Text matching
{"title": {"$contains": "dark"}}
{"title": {"$startsWith": "The"}}
{"title": {"$endsWith": "Returns"}}
# Existence and type checks
{"poster": {"$exists": True}}
{"rating": {"$type": "number"}}
# Logical operators
{"$and": [{"genre": "sci-fi"}, {"rating": {"$gte": 8}}]}
{"$or": [{"genre": "sci-fi"}, {"rating": {"$gte": 9}}]}
{"$not": {"genre": "romance"}}
Full reference: Where Operators
Relationship Traversal
Filter across graph edges inline with where:
- Python
- TypeScript
- shell
# Movies that have an ACTOR from the USA
result = db.records.find({
"labels": ["MOVIE"],
"where": {
"ACTOR": {"country": "USA"}
}
})
# With explicit relationship type and direction
result = db.records.find({
"labels": ["MOVIE"],
"where": {
"ACTOR": {
"$relation": {"type": "STARS_IN", "direction": "in"},
"country": "USA"
}
}
})
// Movies that have an ACTOR from the USA
const { data } = await db.records.find({
labels: ['MOVIE'],
where: {
ACTOR: { country: 'USA' }
}
})
// With explicit relationship type and direction
const { data: films } = await db.records.find({
labels: ['MOVIE'],
where: {
DIRECTOR: {
$relation: { type: 'DIRECTED_BY', direction: 'out' },
name: { $contains: 'Nolan' }
}
}
})
curl -X POST https://api.rushdb.com/api/v1/records/search \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"labels": ["MOVIE"],
"where": {
"ACTOR": {
"$relation": {"type": "STARS_IN", "direction": "in"},
"country": "USA"
}
}
}'
Select Expressions & Aggregations
limit when using selectIt restricts the record scan and produces mathematically incorrect totals. Use orderBy on a select output key instead.
- Python
- TypeScript
- shell
result = db.records.find({
"labels": ["MOVIE"],
"where": {"ACTOR": {"$alias": "$actor", "country": "USA"}},
"select": {
"title": "$record.title",
"actorCount": {"$count": "$actor"},
"avgRating": {"$avg": "$record.rating", "$precision": 1},
"actorNames": {"$collect": {
"from": "$actor",
"select": {"name": "$actor.name"}
}}
}
})
Available expressions: $count · $sum · $avg · $min · $max · $collect · $timeBucket · $ref · $add · $subtract · $multiply · $divide
const stats = await db.records.find({
labels: ['MOVIE'],
where: { ACTOR: { $alias: '$actor', country: 'USA' } },
select: {
title: '$record.title',
actorCount: { $count: '$actor' },
avgRating: { $avg: '$record.rating', $precision: 1 },
actorNames: { $collect: { from: '$actor', select: { name: '$actor.name' } } }
}
})
curl -X POST https://api.rushdb.com/api/v1/records/search \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"labels": ["MOVIE"],
"select": {
"count": {"$count": "*"},
"avgRating": {"$avg": "$record.rating"}
}
}'
Full reference: Select Expressions
Group By
- Python
- TypeScript
- shell
result = db.records.find({
"labels": ["MOVIE"],
"select": {
"count": {"$count": "*"},
"avgRating": {"$avg": "$record.rating"}
},
"groupBy": ["$record.genre"],
"orderBy": {"count": "desc"}
})
# [{"genre": "sci-fi", "count": 42, "avgRating": 7.9}, ...]
const byGenre = await db.records.find({
labels: ['MOVIE'],
select: {
count: { $count: '*' },
avgRating: { $avg: '$record.rating', $precision: 1 }
},
groupBy: ['$record.genre'],
orderBy: { count: 'desc' }
})
// [{ genre: 'sci-fi', count: 42, avgRating: 7.9 }, ...]
curl -X POST https://api.rushdb.com/api/v1/records/search \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"labels": ["MOVIE"],
"select": {
"count": {"$count": "*"},
"avgRating": {"$avg": "$record.rating"}
},
"groupBy": ["$record.genre"],
"orderBy": {"count": "desc"}
}'
Full reference: Group By
TimeBucket (Time-Series)
- Python
- TypeScript
- shell
result = db.records.find({
"labels": ["ORDER"],
"select": {
"day": {"$timeBucket": {"field": "$record.createdAt", "unit": "day"}},
"count": {"$count": "*"}
},
"groupBy": ["day"],
"orderBy": {"day": "asc"}
})
const daily = await db.records.find({
labels: ['ORDER'],
select: {
day: { $timeBucket: { field: '$record.createdAt', unit: 'day' } },
count: { $count: '*' }
},
groupBy: ['day'],
orderBy: { day: 'asc' }
})
curl -X POST https://api.rushdb.com/api/v1/records/search \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"labels": ["ORDER"],
"select": {
"day": {"$timeBucket": {"field": "$record.createdAt", "unit": "day"}},
"count": {"$count": "*"}
},
"groupBy": ["day"],
"orderBy": {"day": "asc"}
}'
unit values: day · week · month · quarter · year · hours · minutes · seconds (use plural + size for custom window widths).
Collect Related Records
Pull related records inline with the query result.
Label-based (preferred for nesting — no alias required):
- Python
- TypeScript
- shell
result = db.records.find({
"labels": ["COMPANY"],
"select": {
"name": "$record.name",
"departments": {
"$collect": {
"label": "DEPARTMENT",
"select": {
"name": "$self.name",
"projects": {
"$collect": {
"label": "PROJECT",
"select": {"name": "$self.name"}
}
}
}
}
}
}
})
const companies = await db.records.find({
labels: ['COMPANY'],
select: {
name: '$record.name',
departments: {
$collect: {
label: 'DEPARTMENT',
select: {
name: '$self.name',
projects: {
$collect: {
label: 'PROJECT',
select: { name: '$self.name' }
}
}
}
}
}
}
})
curl -X POST https://api.rushdb.com/api/v1/records/search \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"labels": ["COMPANY"],
"select": {
"name": "$record.name",
"departments": {
"$collect": {
"label": "DEPARTMENT",
"select": {"name": "$self.name"}
}
}
}
}'
Alias-based (requires $alias in where):
- Python
- TypeScript
- shell
result = db.records.find({
"labels": ["MOVIE"],
"where": {"ACTOR": {"$alias": "$actor"}},
"select": {
"title": "$record.title",
"actors": {
"$collect": {
"from": "$actor",
"select": {"name": "$actor.name", "country": "$actor.country"}
}
}
}
})
const movies = await db.records.find({
labels: ['MOVIE'],
where: { ACTOR: { $alias: '$actor' } },
select: {
title: '$record.title',
actors: {
$collect: {
from: '$actor',
select: { name: '$actor.name', country: '$actor.country' }
}
}
}
})
curl -X POST https://api.rushdb.com/api/v1/records/search \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"labels": ["MOVIE"],
"where": {"ACTOR": {"$alias": "$actor"}},
"select": {
"title": "$record.title",
"actors": {
"$collect": {
"from": "$actor",
"select": {"name": "$actor.name", "country": "$actor.country"}
}
}
}
}'
SearchResult
- Python
- TypeScript
- shell
result = db.records.find({"labels": ["MOVIE"], "limit": 10})
len(result) # records returned in this page (≤ limit)
result.total # total records matching in the database
result.has_more # True if more pages remain
result[0] # access by index
for r in result: # iterable
pass
const { data, total } = await db.records.find({ labels: ['MOVIE'], limit: 10 })
// data: DBRecordInstance[]
// total: number — total records matching in the database
{
"data": [...],
"total": 42
}
Contextual Search (REST)
Search within a specific record's relationships:
POST /api/v1/records/:entityId/search
curl -X POST https://api.rushdb.com/api/v1/records/movie-123/search \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"labels": ["ACTOR"], "where": {"country": "USA"}}'
In a Transaction
- Python
- TypeScript
- shell
tx = db.tx.begin()
try:
result = db.records.find({"labels": ["MOVIE"]}, transaction=tx)
tx.commit()
except Exception:
tx.rollback()
raise
const tx = await db.tx.begin()
try {
const { data } = await db.records.find({ labels: ['MOVIE'] }, tx)
await tx.commit()
} catch (e) {
await tx.rollback()
throw e
}
curl -X POST https://api.rushdb.com/api/v1/records/search \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Transaction-Id: $TX_ID" \
-d '{"labels": ["MOVIE"]}'
TypeScript: Via Model
const MovieModel = new Model('MOVIE', {
title: { type: 'string' },
rating: { type: 'number' }
})
const all = await MovieModel.find()
const sciFi = await MovieModel.find({ where: { genre: 'sci-fi' } })
const one = await MovieModel.findOne({ where: { title: 'Inception' } })
const byId = await MovieModel.findById('movie-id-123')
const unique = await MovieModel.findUniq({ where: { title: 'Inception' } })
Model search methods auto-fill labels from the model definition.
See also
- Where Operators — full operator reference
- Select Expressions — aggregation & output shaping
- Group By — grouping reference
- Pagination & Order — sorting and paging
- Connect Records — traverse and filter relationships
- Semantic Search — vector + filter search