Documentation Index Fetch the complete documentation index at: https://docs.ondb.ai/llms.txt
Use this file to discover all available pages before exploring further.
Create pre-computed views with JOINs and aggregations for instant query performance. Data is pre-computed and updates automatically when source data changes.
Creating Views
Simple View
// Get database manager
const db = client . database ( 'your-app-id' );
// Create a materialized view with SDK
await db . createView ( 'topSellers' , [ 'products' , 'orders' ], {
select: [ 'id' , 'name' , 'price' , 'salesCount' ],
where: { status: 'active' },
orderBy: { salesCount: 'desc' },
limit: 100
});
View with JOINs
// Build complex view with JOINs using query builder
const viewQuery = client . queryBuilder ()
. collection ( 'user_top_tracks' )
. joinOne ( 'user' , 'users' )
. onField ( 'user_id' ). equals ( '$data.user_id' )
. selectFields ([ 'country' ])
. build ()
. orderBy ( 'playcount' )
. selectAll ()
. limit ( 10000 )
. getQueryRequest ();
await db . createView (
'top_tracks_with_countries' ,
[ 'user_top_tracks' , 'users' ],
viewQuery
);
Aggregated Views
Create views with GROUP BY for dashboard analytics:
// View with aggregation
const aggregatedView = {
name: 'plays_by_country' ,
source_collections: [ 'top_tracks_with_countries' ],
query: {
find: {},
select: {},
group_by: [ 'country' ],
aggregate: {
total_plays: { '$sum' : 'playcount' },
unique_tracks: { '$countDistinct' : 'track_name' },
unique_artists: { '$countDistinct' : 'artist_name' }
},
sort_by: [ 'total_plays' ],
limit: 100
}
};
// Create via API
await db . createView (
aggregatedView . name ,
aggregatedView . source_collections ,
aggregatedView . query
);
Managing Views
const db = client . database ( 'your-app-id' );
// List all views
const views = await db . listViews ();
// Get specific view
const view = await db . getView ( 'topSellers' );
// Refresh view data
await db . refreshView ( 'topSellers' );
// Delete view
await db . deleteView ( 'topSellers' );
SQL-Based Views
Create views using SQL syntax with configurable refresh modes:
const db = client . database ( 'your-app-id' );
// Create a live view (refreshes automatically)
await db . createViewSql (
'CREATE VIEW active_users AS SELECT id, name, email FROM your-app-id::users WHERE active = true' ,
'live'
);
// Create a lazy view (refresh manually)
await db . createViewSql (
'CREATE VIEW monthly_summary AS SELECT status, COUNT(*) as total FROM your-app-id::orders GROUP BY status' ,
'lazy'
);
// Query a view
const results = await db . queryView ( 'active_users' );
// Count view records
const count = await db . countView ( 'active_users' );
// Refresh a lazy view manually
await db . refreshView ( 'monthly_summary' );
Querying Views
Query materialized views like regular collections - data is pre-computed and instant:
// Query the view (data is pre-computed)
const results = await client . queryBuilder ()
. collection ( 'top_tracks_with_countries' )
. selectAll ()
. limit ( 1000 )
. execute ();
// View results already include JOINed data
results . records . forEach ( record => {
console . log ( `Track: ${ record . track_name } ` );
console . log ( `Country: ${ record . user . country } ` );
console . log ( `Plays: ${ record . playcount } ` );
});
Aggregation Operators
Operator Description $sumSum values across grouped records $avgAverage values $countCount records in group $countDistinctCount unique values $minMinimum value in group $maxMaximum value in group
Use Cases
Analytics Dashboard
// Create a view for dashboard metrics
await db . createView ( 'daily_metrics' , [ 'orders' ], {
find: {},
select: {},
group_by: [ 'date' ],
aggregate: {
total_orders: { '$count' : '*' },
total_revenue: { '$sum' : 'amount' },
avg_order_value: { '$avg' : 'amount' },
unique_customers: { '$countDistinct' : 'customer_id' }
},
sort_by: [ 'date' ],
limit: 365
});
// Query instantly
const metrics = await db . queryView ( 'daily_metrics' , {
limit: 30 // Last 30 days
});
Leaderboard
// Create leaderboard view
await db . createView ( 'user_leaderboard' , [ 'scores' ], {
find: {},
select: {},
group_by: [ 'user_id' ],
aggregate: {
total_score: { '$sum' : 'points' },
games_played: { '$count' : '*' },
highest_score: { '$max' : 'points' }
},
sort_by: [ 'total_score' ],
limit: 100
});
Denormalized Feed
// Create a denormalized feed with user info
const feedQuery = client . queryBuilder ()
. collection ( 'posts' )
. joinOne ( 'author' , 'users' )
. onField ( 'id' ). equals ( '$data.author_id' )
. selectFields ([ 'name' , 'avatar' , 'verified' ])
. build ()
. joinMany ( 'recent_comments' , 'comments' )
. onField ( 'post_id' ). equals ( '$data.id' )
. selectFields ([ 'id' , 'content' , 'author_name' ])
. build ()
. orderBy ( 'created_at' , 'DESC' )
. selectAll ()
. limit ( 1000 )
. getQueryRequest ();
await db . createView ( 'feed' , [ 'posts' , 'users' , 'comments' ], feedQuery );
Aspect Regular Query Materialized View Complex JOINs Computed per request Pre-computed Aggregations Full table scan Pre-calculated Response time Variable Instant Cost Per-query computation Storage only
When to Use Views
Use materialized views when:
Queries are complex (multiple JOINs, aggregations)
Data is queried frequently
Real-time freshness is not critical
Dashboard or analytics scenarios
Use regular queries when:
Data must be real-time fresh
Queries are simple
Data changes frequently and views would need constant refresh
Next Steps
CRUD Operations Document operations
Query Builder Build complex queries