Nimbu.Query
Nimbu.Query allows you to retrieve objects from Nimbu by specifying search criteria. It provides a powerful and flexible way to filter, sort, and paginate your data.
Creating Queries
Basic Query
js
// Query a channel
const query = new Nimbu.Query('blog');
// Query using a subclass
const Product = Nimbu.Object.extend('products');
const query = new Nimbu.Query(Product);Executing Queries
Get All Results
js
const query = new Nimbu.Query('products');
const products = await query.collection().fetch();
console.log(`Found ${products.length} products`);Get First Result
js
const query = new Nimbu.Query('customers');
query.equalTo('email', '[email protected]');
const customer = await query.first();
if (customer) {
console.log('Found customer:', customer.get('name'));
} else {
console.log('Customer not found');
}Get by ID
js
const query = new Nimbu.Query('products');
const product = await query.get('product_id_here');
console.log('Product:', product.get('name'));Count Results
js
const query = new Nimbu.Query('customers');
query.equalTo('newsletter_subscribed', true);
const count = await query.count();
console.log(`${count} subscribers`);Basic Constraints
Equal To
js
query.equalTo('status', 'active');
query.equalTo('category', 'electronics');
query.equalTo('featured', true);Not Equal To
js
query.notEqualTo('status', 'deleted');
query.notEqualTo('stock', 0);Greater Than / Less Than
js
// Greater than
query.greaterThan('price', 50);
query.greaterThan('stock', 0);
// Greater than or equal to
query.greaterThanOrEqualTo('age', 18);
// Less than
query.lessThan('price', 100);
// Less than or equal to
query.lessThanOrEqualTo('stock', 10);Contained In (Array)
js
// Match any of these values
query.containedIn('status', ['active', 'pending', 'processing']);
query.containedIn('category', ['books', 'magazines']);Not Contained In
js
query.notContainedIn('status', ['deleted', 'archived']);Contains All
js
// Object must have all these tags
query.containsAll('tags', ['featured', 'sale']);Exists
js
// Field must exist and not be null/undefined
query.exists('email');
query.exists('shipping_address');
// Field must not exist or be null
query.doesNotExist('deleted_at');Text Matching
Starts With
js
query.startsWith('name', 'John');
query.startsWith('email', 'admin@');Ends With
js
query.endsWith('email', '@example.com');
query.endsWith('title', '?');Contains (Substring)
js
query.contains('description', 'sale');
query.contains('title', 'guide');Matches (Regex)
js
// Case-insensitive search
query.matches('name', 'john', 'i');
// Email pattern
query.matches('email', '^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$');Sorting
Ascending Order
js
query.ascending('created_at');
query.ascending('name');
query.ascending('price');Descending Order
js
query.descending('created_at');
query.descending('price');
query.descending('popularity');Multiple Sort Orders
js
// Sort by category ascending, then price descending
query.ascending('category');
query.descending('price');Limiting and Pagination
Limit Results
js
// Get only first 10 results
query.limit(10);
// Get first 50 results
query.limit(50);Skip Results
js
// Skip first 10 results (for pagination)
query.skip(10);
// Page 2 with 20 items per page
const page = 2;
const perPage = 20;
query.limit(perPage);
query.skip((page - 1) * perPage);Pagination Example
js
async function getPage(pageNumber, pageSize = 20) {
const query = new Nimbu.Query('products');
query.equalTo('active', true);
query.limit(pageSize);
query.skip((pageNumber - 1) * pageSize);
query.descending('created_at');
const products = await query.collection().fetch();
const total = await query.count();
return {
products,
page: pageNumber,
pageSize,
totalPages: Math.ceil(total / pageSize),
total
};
}
// Usage
const page1 = await getPage(1);
console.log(`Page 1: ${page1.products.length} of ${page1.total} products`);Working with Relations
Include Related Objects
js
// Fetch books with their authors in one query
const query = new Nimbu.Query('books');
query.include('author');
const books = await query.collection().fetch();
books.forEach(book => {
const author = book.get('author');
console.log(`${book.get('title')} by ${author.get('name')}`);
});Include Multiple Relations
js
query.include('author');
query.include('publisher');
query.include('category');
// Or include nested relations
query.include('author.country');Query by Related Object
js
// Find books by a specific author
const author = await new Nimbu.Query('authors').get(authorId);
const query = new Nimbu.Query('books');
query.equalTo('author', author);
const booksByAuthor = await query.collection().fetch();Query a Relation
js
// Get a customer's favorite products
const customer = await new Nimbu.Query('customers').get(customerId);
const favorites = customer.relation('favorite_products');
const favoriteProducts = await favorites.query()
.descending('created_at')
.collection()
.fetch();Compound Queries
AND Conditions (Default)
js
// All conditions must match (AND)
query.equalTo('status', 'active');
query.greaterThan('price', 10);
query.lessThan('price', 100);
// Results: active AND price > 10 AND price < 100OR Queries
js
const query1 = new Nimbu.Query('products');
query1.equalTo('category', 'books');
const query2 = new Nimbu.Query('products');
query2.equalTo('category', 'magazines');
// Combine with OR
const mainQuery = Nimbu.Query.or(query1, query2);
// Results: category = books OR category = magazines
const results = await mainQuery.collection().fetch();Complex Conditions
js
// (category = books AND price < 20) OR (category = magazines)
const affordableBooks = new Nimbu.Query('products');
affordableBooks.equalTo('category', 'books');
affordableBooks.lessThan('price', 20);
const magazines = new Nimbu.Query('products');
magazines.equalTo('category', 'magazines');
const query = Nimbu.Query.or(affordableBooks, magazines);Common Query Patterns
Find Active Items
js
const query = new Nimbu.Query('products');
query.equalTo('active', true);
query.greaterThan('stock', 0);
query.descending('created_at');
query.limit(20);
const products = await query.collection().fetch();Search by Email
js
const query = new Nimbu.Query('customers');
query.equalTo('email', email.toLowerCase());
const customer = await query.first();Recent Items
js
const oneDayAgo = new Date();
oneDayAgo.setDate(oneDayAgo.getDate() - 1);
const query = new Nimbu.Query('orders');
query.greaterThan('created_at', oneDayAgo);
query.descending('created_at');
const recentOrders = await query.collection().fetch();Range Queries
js
// Products between $10 and $50
const query = new Nimbu.Query('products');
query.greaterThanOrEqualTo('price', 10);
query.lessThanOrEqualTo('price', 50);
const products = await query.collection().fetch();Search with Filters
js
async function searchProducts(filters) {
const query = new Nimbu.Query('products');
query.equalTo('active', true);
if (filters.category) {
query.equalTo('category', filters.category);
}
if (filters.minPrice) {
query.greaterThanOrEqualTo('price', filters.minPrice);
}
if (filters.maxPrice) {
query.lessThanOrEqualTo('price', filters.maxPrice);
}
if (filters.search) {
query.matches('name', filters.search, 'i');
}
query.limit(filters.limit || 20);
query.skip(filters.skip || 0);
return await query.collection().fetch();
}
// Usage
const results = await searchProducts({
category: 'electronics',
minPrice: 50,
maxPrice: 500,
search: 'wireless',
limit: 10
});Advanced Techniques
Select Specific Fields
js
// Only fetch specific fields (saves bandwidth)
query.select('name', 'price', 'stock');
const products = await query.collection().fetch();
// products will only have name, price, and stock fieldsExclude Fields
js
// Fetch all fields except these
query.exclude('large_description', 'internal_notes');Find Distinct Values
js
const query = new Nimbu.Query('products');
query.distinct('category');
const categories = await query.collection().fetch();Error Handling
Handle Query Errors
js
try {
const query = new Nimbu.Query('products');
const products = await query.collection().fetch();
console.log(`Found ${products.length} products`);
} catch (error) {
console.error('Query failed:', error.message);
if (error.code === 101) {
console.error('Object not found');
}
}Validate Before Querying
js
async function safeQuery(className, constraints) {
if (!className) {
throw new Error('className is required');
}
const query = new Nimbu.Query(className);
// Apply constraints
Object.entries(constraints).forEach(([key, value]) => {
query.equalTo(key, value);
});
try {
return await query.collection().fetch();
} catch (error) {
console.error(`Query failed for ${className}:`, error.message);
return [];
}
}Performance Tips
1. Use Specific Queries
js
// Good: Specific query
query.equalTo('status', 'active');
query.equalTo('category', 'books');
const results = await query.collection().fetch();
// Avoid: Fetch all then filter
const all = await query.collection().fetch();
const filtered = all.filter(item => item.get('status') === 'active');2. Limit Results
js
// Good: Limit to what you need
query.limit(20);
// Avoid: Fetching thousands of records
const all = await query.collection().fetch(); // Could be huge!3. Use Count for Numbers
js
// Good: Just count
const count = await query.count();
// Avoid: Fetch all to count
const all = await query.collection().fetch();
const count = all.length;4. Select Only Needed Fields
js
// Good: Select specific fields
query.select('name', 'price');
// Avoid: Fetch all fields when you only need a few5. Use Includes for Relations
js
// Good: One query with includes
query.include('author');
const books = await query.collection().fetch();
// Avoid: N+1 queries
const books = await query.collection().fetch();
for (const book of books) {
await book.get('author').fetch(); // Separate query each time!
}Real-World Examples
Newsletter Subscribers
js
async function getNewsletterSubscribers() {
const query = new Nimbu.Query('customers');
query.equalTo('newsletter_subscribed', true);
query.exists('email');
query.select('email', 'name');
return await query.collection().fetch();
}Low Stock Products
js
async function getLowStockProducts(threshold = 10) {
const query = new Nimbu.Query('products');
query.equalTo('active', true);
query.lessThanOrEqualTo('stock', threshold);
query.greaterThan('stock', 0);
query.ascending('stock');
return await query.collection().fetch();
}Pending Orders
js
async function getPendingOrders(limit = 50) {
const query = new Nimbu.Query('orders');
query.containedIn('status', ['pending', 'processing']);
query.descending('created_at');
query.limit(limit);
query.include('customer');
return await query.collection().fetch();
}Next Steps
- Learn about Nimbu.Object - Working with data objects
- Explore Other Classes - Customer, Product, Order, etc.
- Review Cloud Functions - Use queries in functions
- Check Background Jobs - Use queries in scheduled tasks