Skip to main content

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

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"])

Find One

Returns the first matching record, or null / None if none found.

db.records.find_one()

movie = db.records.find_one({
"labels": ["MOVIE"],
"where": {"title": "Inception"}
})

Find Unique

Like find_one / findOne, but throws NonUniqueResultError if more than one record matches.

db.records.find_uniq()

movie = db.records.find_uniq({
"labels": ["MOVIE"],
"where": {"title": "Inception"}
})

Search Records

Full search with filtering, sorting, and pagination.

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")

SearchQuery parameters

FieldTypeDescription
labelsstring[]Filter by one or more labels
whereobjectField conditions and operators (see Where Operators)
orderBystring | objectSort criteria (see Pagination & Order)
limitnumberMax records to return (default: 1000). Omit when using select
skipnumberRecords to skip for pagination
selectobjectOutput-shaping expressions (see Select Expressions)
groupBystring[]Grouping keys, e.g. ['$record.genre']

Where Operators

Python
# 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:

# 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"
}
}
})

Select Expressions & Aggregations

Do not set limit when using select

It restricts the record scan and produces mathematically incorrect totals. Use orderBy on a select output key instead.

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

Full reference: Select Expressions


Group By

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}, ...]

Full reference: Group By


TimeBucket (Time-Series)

result = db.records.find({
"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).


Pull related records inline with the query result.

Label-based (preferred for nesting — no alias required):

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"}
}
}
}
}
}
}
})

Alias-based (requires $alias in where):

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"}
}
}
}
})

SearchResult

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

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

tx = db.tx.begin()
try:
result = db.records.find({"labels": ["MOVIE"]}, transaction=tx)
tx.commit()
except Exception:
tx.rollback()
raise

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