Querying¶
SurrealEngine provides a powerful QuerySet API for building and executing database queries with a Django-style interface. This guide covers the query building features and operators available in SurrealEngine.
Basic Querying¶
Use the objects manager to build queries on your document models:
from surrealengine import Document, StringField, IntField
class User(Document):
name = StringField(required=True)
age = IntField()
status = StringField()
class Meta:
collection = "users"
# Get all users
users = await User.objects.all()
# Filter users
active_users = await User.objects.filter(status="active")
# Chain filters
young_active = await User.objects.filter(status="active").filter(age__lt=30)
Field Selection¶
Omit Fields (v0.5.0+)¶
Exclude specific fields from query results to reduce data transfer:
# Omit sensitive fields
users = await User.objects.omit("password", "email").all()
# Combine with filters
users = await User.objects.filter(status="active").omit("password")
Select Specific Fields¶
Use only() to select only specific fields:
# Only get name and age
users = await User.objects.only("name", "age").all()
Query Performance¶
Timeout (v0.5.0+)¶
Set a timeout for query execution to prevent long-running queries:
# 5 second timeout
users = await User.objects.timeout("5s").all()
# 1 minute timeout
users = await User.objects.timeout("1m").filter(status="active")
Tempfiles (v0.5.0+)¶
Enable or disable temporary files for large query results:
# Enable tempfiles for large result sets
users = await User.objects.tempfiles(True).all()
# Disable tempfiles (default)
users = await User.objects.tempfiles(False).all()
Index Control (v0.5.0+)¶
Bypass indexes for specific queries:
# Don't use any indexes
users = await User.objects.no_index().filter(name="John")
Query Explanation (v0.5.0+)¶
Analyze query execution plans:
# Get basic execution plan
plan = await User.objects.filter(status="active").explain()
print(plan)
# Get full execution plan with trace
full_plan = await User.objects.filter(status="active").explain(full=True)
print(full_plan)
# Using the builder pattern
plan = await User.objects.filter(status="active").with_explain().all()
# Synchronous version
plan = User.objects.filter(status="active").explain_sync()
Advanced Filter Operators¶
Set Operators (v0.5.0+)¶
SurrealEngine supports advanced set operators for filtering:
# Contains any - check if field contains any of the values
users = await User.objects.filter(tags__contains_any=["python", "javascript"])
# Contains all - check if field contains all of the values
users = await User.objects.filter(tags__contains_all=["python", "javascript", "rust"])
# Contains none - check if field contains none of the values
users = await User.objects.filter(tags__contains_none=["php", "perl"])
# Inside - check if value is in the list
users = await User.objects.filter(status__inside=["active", "pending"])
# Not inside - check if value is not in the list
users = await User.objects.filter(status__not_inside=["banned", "deleted"])
# All inside - check if all field values are in the list
users = await User.objects.filter(tags__all_inside=["python", "javascript", "rust", "go"])
# Any inside - check if any field value is in the list
users = await User.objects.filter(tags__any_inside=["python", "javascript"])
# None inside - check if no field values are in the list
users = await User.objects.filter(tags__none_inside=["php", "perl"])
Standard Operators¶
# Equality
users = await User.objects.filter(name="John")
users = await User.objects.filter(name__eq="John")
# Inequality
users = await User.objects.filter(status__ne="banned")
# Greater than / Less than
users = await User.objects.filter(age__gt=18)
users = await User.objects.filter(age__gte=18)
users = await User.objects.filter(age__lt=65)
users = await User.objects.filter(age__lte=65)
# String operations
users = await User.objects.filter(name__contains="John")
users = await User.objects.filter(name__startswith="J")
users = await User.objects.filter(name__endswith="son")
users = await User.objects.filter(email__regex=r".*@example\.com")
# In operator
users = await User.objects.filter(status__in=["active", "pending"])
Grouping and Aggregation¶
Group By (v0.5.0+)¶
Group query results by one or more fields:
# Group by single field
results = await User.objects.group_by("status").all()
# Group by multiple fields
results = await User.objects.group_by("status", "age").all()
# Group all results (v0.5.0+)
results = await User.objects.group_by(all=True).all()
Complex Queries with Q Objects¶
Use Q objects for complex boolean logic:
from surrealengine import Q
# OR condition
users = await User.objects.filter(
Q(status="active") | Q(status="pending")
)
# AND condition
users = await User.objects.filter(
Q(status="active") & Q(age__gt=18)
)
# NOT condition
users = await User.objects.filter(~Q(status="banned"))
# Complex nested conditions
users = await User.objects.filter(
Q(status="active") & (Q(age__lt=18) | Q(age__gt=65))
)
Ordering and Pagination¶
# Order by field
users = await User.objects.order_by("name")
# Descending order
users = await User.objects.order_by("-age")
# Multiple fields
users = await User.objects.order_by("status", "-age")
# Limit results
users = await User.objects.limit(10)
# Skip results
users = await User.objects.offset(20)
# Pagination
page = await User.objects.page(1, 20) # page 1, 20 items per page
Synchronous Queries¶
All query methods have synchronous equivalents:
# Synchronous query
users = User.objects.filter(status="active").all_sync()
# Synchronous explain
plan = User.objects.filter(status="active").explain_sync()
# Get single object
user = User.objects.get_sync(id="user:123")
Query Chaining¶
All QuerySet methods return a new QuerySet, allowing for flexible query building:
# Build query progressively
query = User.objects.filter(status="active")
query = query.filter(age__gte=18)
query = query.omit("password")
query = query.timeout("5s")
query = query.order_by("-created_at")
# Execute
users = await query.all()
# Or chain in one statement
users = await (User.objects
.filter(status="active")
.filter(age__gte=18)
.omit("password")
.timeout("5s")
.order_by("-created_at")
.all())