Overview
GenosDB provides a MongoDB-style query language with advanced operators for filtering, text search, pattern matching, and logical combinations. The map() method is your primary tool for querying data.
Basic Query Structure
import { gdb } from 'genosdb'
const db = await gdb ( 'my-app' )
const { results } = await db . map ({
query: { /* filter conditions */ },
field: 'fieldName' , // Sort by this field
order: 'asc' , // or 'desc'
$limit: 10 // Maximum results
})
Comparison Operators
Equality: $eq
// Find users named "Alice"
const { results } = await db . map ({
query: { name: { $eq: 'Alice' } }
})
// Shorthand (implicit $eq)
const { results } = await db . map ({
query: { name: 'Alice' }
})
Inequality: $ne
// Find all posts except drafts
const { results } = await db . map ({
query: { status: { $ne: 'draft' } }
})
Greater Than: $gt and $gte
// Users older than 18
const { results } = await db . map ({
query: { age: { $gt: 18 } }
})
// Users 18 or older
const { results } = await db . map ({
query: { age: { $gte: 18 } }
})
Less Than: $lt and $lte
// Products under $50
const { results } = await db . map ({
query: { price: { $lt: 50 } }
})
// Products $50 or less
const { results } = await db . map ({
query: { price: { $lte: 50 } }
})
Range: $between
// Users between 18 and 30 years old
const { results } = await db . map ({
query: { age: { $between: [ 18 , 30 ] } }
})
// Posts from last week
const weekAgo = new Date ( Date . now () - 7 * 24 * 60 * 60 * 1000 ). toISOString ()
const now = new Date (). toISOString ()
const { results } = await db . map ({
query: {
createdAt: { $between: [ weekAgo , now ] }
}
})
$between works with numbers, dates (ISO strings), and any comparable values.
In Array: $in
// Users with specific statuses
const { results } = await db . map ({
query: {
status: { $in: [ 'active' , 'pending' , 'verified' ] }
}
})
// Multiple ID lookup
const { results } = await db . map ({
query: {
id: { $in: [ 'user1' , 'user2' , 'user3' ] }
}
})
Field Existence: $exists
// Nodes with an email field
const { results } = await db . map ({
query: { email: { $exists: true } }
})
// Nodes without a deleted field
const { results } = await db . map ({
query: { deleted: { $exists: false } }
})
Text Search Operators
Full-Text Search: $text
// Search across all fields (case-insensitive, diacritic-normalized)
const { results } = await db . map ({
query: { $text: 'alice' }
})
// Search specific field
const { results } = await db . map ({
query: {
name: { $text: 'alice' }
}
})
// Search nested fields
const { results } = await db . map ({
query: {
'profile.bio' : { $text: 'developer' }
}
})
$text performs case-insensitive, diacritic-normalized searching. “ali” matches “Alice”, “Éric” matches “eric”.
Pattern Matching: $like
SQL-style pattern matching with wildcards:
// Names starting with 'J'
const { results } = await db . map ({
query: { name: { $like: 'J%' } }
})
// Names ending with 'son'
const { results } = await db . map ({
query: { name: { $like: '%son' } }
})
// Names containing 'and'
const { results } = await db . map ({
query: { name: { $like: '%and%' } }
})
% Matches any sequence of characters 'J%' → John, Jane, James
_ Matches exactly one character 'J_n' → Jan, Jon (not John)
Regular Expressions: $regex
// Names starting with J (regex)
const { results } = await db . map ({
query: { name: { $regex: '^J' } }
})
// Email validation
const { results } = await db . map ({
query: {
email: { $regex: '^[^@]+@[^@]+ \\ .[^@]+$' }
}
})
// Phone numbers (US format)
const { results } = await db . map ({
query: {
phone: { $regex: '^ \\ d{3}- \\ d{3}- \\ d{4}$' }
}
})
Remember to escape backslashes in regex patterns: \\d not \d.
Logical Operators
AND: $and
// Users who are active AND over 18
const { results } = await db . map ({
query: {
$and: [
{ status: 'active' },
{ age: { $gt: 18 } }
]
}
})
// Implicit AND (multiple conditions at root level)
const { results } = await db . map ({
query: {
status: 'active' ,
age: { $gt: 18 }
}
})
OR: $or
// Users who are admins OR moderators
const { results } = await db . map ({
query: {
$or: [
{ role: 'admin' },
{ role: 'moderator' }
]
}
})
// Complex OR conditions
const { results } = await db . map ({
query: {
$or: [
{ age: { $lt: 18 } },
{ age: { $gt: 65 } },
{ status: 'vip' }
]
}
})
NOT: $not
// Users NOT over 18
const { results } = await db . map ({
query: {
$not: { age: { $gt: 18 } }
}
})
// Combining NOT with other operators
const { results } = await db . map ({
query: {
status: 'active' ,
$not: { role: 'guest' }
}
})
Complex Logical Combinations
// (Active OR Pending) AND (Age > 18) AND NOT (Role = guest)
const { results } = await db . map ({
query: {
$and: [
{
$or: [
{ status: 'active' },
{ status: 'pending' }
]
},
{ age: { $gt: 18 } },
{ $not: { role: 'guest' } }
]
}
})
Nested Field Queries
Use dot notation to query nested properties:
// User with nested profile
await db . put ({
name: 'Alice' ,
profile: {
bio: 'Software engineer' ,
location: {
city: 'San Francisco' ,
country: 'USA'
}
}
}, 'user:alice' )
// Query nested fields
const { results } = await db . map ({
query: {
'profile.location.city' : 'San Francisco'
}
})
// With operators
const { results } = await db . map ({
query: {
'profile.bio' : { $text: 'engineer' }
}
})
Sorting Results
Basic Sorting
// Sort by age (ascending)
const { results } = await db . map ({
query: { type: 'user' },
field: 'age' ,
order: 'asc'
})
// Sort by name (descending)
const { results } = await db . map ({
query: { type: 'user' },
field: 'name' ,
order: 'desc'
})
Sorting Nested Fields
const { results } = await db . map ({
query: { type: 'user' },
field: 'profile.location.city' ,
order: 'asc'
})
Default Sorting
If no field is specified, results are returned in insertion order:
// Insertion order (oldest first)
const { results } = await db . map ({
query: { type: 'post' }
})
GenosDB supports cursor-based pagination for efficient traversal of large datasets.
Limit Results: $limit
// Get first 10 users
const { results } = await db . map ({
query: { type: 'user' },
$limit: 10
})
// First page
const page1 = await db . map ({
query: { type: 'post' },
field: 'createdAt' ,
order: 'desc' ,
$limit: 10
})
// Get last ID from page 1
const lastId = page1 . results [ page1 . results . length - 1 ]. id
// Second page
const page2 = await db . map ({
query: { type: 'post' },
field: 'createdAt' ,
order: 'desc' ,
$limit: 10 ,
$after: lastId // Start after last ID from page 1
})
// Get 10 posts before a specific ID
const { results } = await db . map ({
query: { type: 'post' },
field: 'createdAt' ,
order: 'desc' ,
$limit: 10 ,
$before: 'post:123'
})
let currentCursor = null
const cursors = [] // Stack for backward navigation
function nextPage () {
const { results } = await db . map ({
query: { type: 'post' },
field: 'createdAt' ,
order: 'desc' ,
$limit: 15 ,
$after: currentCursor
})
if ( results . length > 0 ) {
cursors . push ( currentCursor ) // Save for backward navigation
currentCursor = results [ results . length - 1 ]. id
displayPosts ( results )
}
}
function previousPage () {
if ( cursors . length > 0 ) {
currentCursor = cursors . pop ()
const { results } = await db . map ({
query: { type: 'post' },
field: 'createdAt' ,
order: 'desc' ,
$limit: 15 ,
$after: currentCursor
})
displayPosts ( results )
}
}
Cursor-based pagination is more efficient than offset-based for large datasets and remains stable when data changes.
Use Specific Queries Narrow queries return faster: // Good
{ type : 'user' , status : 'active' }
// Slower
{ type : 'user' }
Limit Results Always use $limit for large datasets: { query : { ... }, $limit : 50 }
Index with Radix Module Enable the Radix indexer for prefix searches: const db = await gdb ( 'app' , { rx: true })
Avoid $regex in Hot Paths Regex is powerful but slower than simple equality.
Complete Query Examples
E-Commerce Product Search
// Find affordable laptops in stock
const { results } = await db . map ({
query: {
$and: [
{ category: 'electronics' },
{ type: 'laptop' },
{ price: { $between: [ 500 , 1500 ] } },
{ inStock: true },
{
$or: [
{ brand: 'Apple' },
{ brand: 'Dell' },
{ brand: 'Lenovo' }
]
}
]
},
field: 'price' ,
order: 'asc' ,
$limit: 20
})
Social Network User Search
// Find active users from San Francisco who are developers
const { results } = await db . map ({
query: {
status: 'active' ,
'profile.location.city' : 'San Francisco' ,
'profile.occupation' : { $text: 'developer' },
age: { $gte: 18 },
email: { $exists: true }
},
field: 'profile.name' ,
order: 'asc' ,
$limit: 50
})
Blog Post Filtering
// Recent published posts with specific tags
const oneMonthAgo = new Date ( Date . now () - 30 * 24 * 60 * 60 * 1000 ). toISOString ()
const { results } = await db . map ({
query: {
type: 'post' ,
status: 'published' ,
publishedAt: { $gt: oneMonthAgo },
$or: [
{ tags: { $in: [ 'javascript' , 'react' , 'vue' ] } },
{ title: { $text: 'tutorial' } }
],
deleted: { $ne: true }
},
field: 'publishedAt' ,
order: 'desc' ,
$limit: 10
})
Query All Nodes
// Get everything (use with caution on large databases)
const { results } = await db . map ({
query: {} // Empty query matches all nodes
})
// Better: Use limit
const { results } = await db . map ({
query: {},
$limit: 100
})
Querying all nodes without a limit can be slow on large databases. Always use $limit for production applications.
Inverted Index Module
For enhanced text search performance, enable the Inverted Index module:
const db = await gdb ( 'my-app' , {
ii: true // Enable inverted index
})
// Now $text searches are significantly faster
const { results } = await db . map ({
query: { $text: 'search term' }
})
The Inverted Index module builds reverse indices for text fields, dramatically improving $text search performance on large datasets.
Graph Traversal Learn the $edge operator for recursive queries
Real-Time Subscriptions Make queries reactive with live updates
CRUD Operations Understand put, get, and remove operations
Search Example See query operators in action