Query your entities
Before going further be sure you completed Getting started
Learn how to query Torii gRPC
Torii gRPC query & clause documentation
Using the QueryBuilder
The QueryBuilder provides a fluent interface to construct queries for your entities. It allows you to organize your queries by namespace and entity, making it easy to build complex queries in a type-safe manner.
Basic Usage
Here's a simple example of how to use the QueryBuilder:
import { ToriiQueryBuilder, MemberClause } from "@dojoengine/sdk";
// Basic query for a player with specific ID and name
const query = new ToriiQueryBuilder()
.withClause(
MemberClause("world-Player", "id", "Eq", "1")
.and(MemberClause("world-Player", "name", "Eq", "Alice"))
.build()
)
.build();
// Execute the query
const entities = await sdk.getEntities(query);
Query Operators
The QueryBuilder supports various operators for filtering entities:
Eq
- Equality comparisonNeq
- Not equal comparisonGt
- Greater than comparisonGte
- Greater than or equal comparisonLt
- Less than comparisonLte
- Less than or equal comparisonIn
- Value is in a listNotIn
- Value is not in a list
Complex Queries
You can build complex queries using AND/OR combinations:
import { ToriiQueryBuilder, MemberClause, AndComposeClause, OrComposeClause } from "@dojoengine/sdk";
// Complex query with AND/OR combinations
const query = new ToriiQueryBuilder()
.withClause(
AndComposeClause([
// First condition: score > 100
MemberClause("world-Player", "score", "Gt", 100),
// Second condition: name is either "Bob" or "Alice"
OrComposeClause([
MemberClause("world-Player", "name", "Eq", "Bob"),
MemberClause("world-Player", "name", "Eq", "Alice")
]),
// Third condition: durability < 50
MemberClause("world-Item", "durability", "Lt", 50)
]).build()
)
.build();
const entities = await sdk.getEntities(query);
Subscribing to Entity Changes
To subscribe to entity changes, you need to first query your model and then subscribe using the entityIds:
import { ToriiQueryBuilder, MemberClause, AndComposeClause } from "@dojoengine/sdk";
// Subscribe to item updates with specific conditions
const [initialEntities, subscription] = await sdk.subscribeEntities({
query: new ToriiQueryBuilder()
.withClause(
AndComposeClause([
MemberClause("world-Item", "type", "Eq", "sword"),
MemberClause("world-Item", "durability", "Eq", 5)
]).build()
)
// IMPORTANT: Include hashedKeys to be able to subscribe to changes
// as we need entityIds to subscribe to changes.
// If you provide a KeysClause, this will be used to subscribe to changes.
// so that you can subscribe to keys patterns instead of entityIds.
.includeHashedKeys(),
callback: ({ data, error }) => {
if (data) {
console.log("Updated entities:", data);
}
if (error) {
console.error("Subscription error:", error);
}
}
});
Pagination and Ordering
You can add pagination and ordering to your queries:
import { ToriiQueryBuilder, MemberClause } from "@dojoengine/sdk";
const query = new ToriiQueryBuilder()
.withClause(
MemberClause("world-Player", "score", "Gt", 0).build()
)
.limit(10) // Limit results to 10 entities
.offset(0) // Start from the first result
.orderBy("world-Player", "score", "Desc") // Order by score in descending order
.build();
const entities = await sdk.getEntities(query);
Best Practices
- Type Safety: Always use TypeScript to ensure type safety in your queries
- Query Organization: Group related conditions using AND/OR combinations
- Performance: Use pagination for large datasets
- Error Handling: Always handle potential errors in subscriptions
- Model Names: Use the correct model names with namespace prefix (e.g., "world-Player")
- Query Optimization: Use appropriate operators for your use case (e.g.,
Eq
for exact matches)
Common Use Cases
Querying Players in a Specific Area
const query = new ToriiQueryBuilder()
.withClause(
AndComposeClause([
MemberClause("world-Position", "x", "Gte", 0),
MemberClause("world-Position", "x", "Lt", 100),
MemberClause("world-Position", "y", "Gte", 0),
MemberClause("world-Position", "y", "Lt", 100)
]).build()
)
.build();
Finding Active Players with Available Moves
const query = new ToriiQueryBuilder()
.withClause(
AndComposeClause([
MemberClause("world-Moves", "remaining", "Gt", 0),
MemberClause("world-Moves", "can_move", "Eq", true)
]).build()
)
.build();
React Integration
When using the QueryBuilder with React, you can use the provided hooks:
import { useEntityQuery, useModels, useModel } from "@dojoengine/sdk/react";
// Inside your React component
function GameComponent() {
// Query entities and automatically subscribe to changes + binding to store
useEntityQuery(
new ToriiQueryBuilder()
.withClause(
MemberClause("world-Item", "durability", "Eq", 2).build()
)
.includeHashedKeys()
);
// Get all items
const items = useModels("world-Item");
// Get a single item by ID
const entityId = useEntityId(1);
const item = useModel(entityId, "world-Item");
return (
// Your component JSX
);
}
This documentation provides a clear overview of the QueryBuilder's functionality, including:
- Basic usage
- Query operators
- Complex queries
- Subscribing to entity changes
- Pagination and ordering
- Best practices
- Common use cases
- React integration