Skip to content

BaseQL

BaseQL is Singlebase's unified query language for all operations. Inspired by MongoDB's powerful operators, BaseQL simplifies the syntax and extends it across your entire backend - not just databases.

Overview

BaseQL - One language for your entire backend. Simple JSON structure, powerful operators, and dynamic expressions that work consistently across database queries, authentication, file storage, AI operations, and vector search.

Key features:

  • Unified syntax across all APIs
  • MongoDB-inspired operators with cleaner syntax
  • Built-in expressions and transformations
  • Learn once, use everywhere

Compare with MongoDB →


Basic Syntax

Every BaseQL request is a JSON object with an op field:

json
{
  "op": "operation_name",
  "collection": "collection_name",
  "filter": { },
  "data": { }
}

Required field:

  • op - The operation to perform

Common fields:

  • collection - Target collection
  • filter - Match criteria (Filter Operators)
  • data - Data to insert/update (Data Operators)
  • output - Result formatting (Output Expressions)
  • limit, offset, page, per_page - Pagination
  • sort - Sorting
  • lookup - Joins

Dot Notation

Access nested fields using dot notation anywhere in BaseQL:

json
{
  "filter": {
    "user.profile.age:$gte": 18,
    "address.city": "New York"
  },
  "data": {
    "user.name": "John Doe",
    "stats.score:$incr": 10
  },
  "output": {
    "$city": "address.city",
    "location": "{{ address.city }}, {{ address.state }}"
  }
}

Filter Operators

Match documents in filter using :$operator syntax.

json
{
  "filter": {
    "age:$gte": 18,
    "price:$between": [10, 100],
    "status:$in": ["active", "premium"],
    "tags:$includes": "featured",
    "$or": [
      { "role": "admin" },
      { "verified": true }
    ]
  }
}

View all Filter Operators →


Data Operators

Transform data in data using :$operator syntax.

json
{
  "data": {
    "name": "John Doe",
    "score:$incr": 10,
    "credits:$decr": 5,
    "tags:$push": "premium",
    "created_at:$now": true,
    "id:$uuid4": true
  }
}

View all Data Operators →


Template Expressions

Dynamic transformations using expressions in data and output.

json
{
  "greeting": "Hello {{ name }}!",
  "total": "?{{ price * quantity }}",
  "$full_name": "first_name + ' ' + last_name",
  "formatted_date": "{{ @formatdate(created_at, 'YYYY-MM-DD') }}",
  "$item_count": "@len(items)"
}

Expression types:

  • {{ expr }} - String template
  • ?{{ expr }} - Native type (number, boolean)
  • $field - Shorthand for native type
  • @function() - Helper functions

View Template Expressions →
View Helper Functions →


Output Expressions

Reshape query results in output.

json
{
  "output": {
    "display_name": "{{ first_name }} {{ last_name }}",
    "$age": "age",
    "is_adult": "?{{ age >= 18 }}"
  }
}

Select specific fields:

json
{ "output": "{name, email, age}" }

Select all fields:

json
{ "output": "**" }

Extend all fields:

json
{
  "output": {
    "_": "**",
    "$full_name": "first_name + ' ' + last_name"
  }
}

View Output Expressions →


Examples

Query

json
{
  "op": "db.find",
  "collection": "products",
  "filter": {
    "price:$between": [10, 100],
    "category:$in": ["electronics", "gadgets"],
    "stock:$gt": 0
  },
  "sort": "price asc",
  "limit": 20
}

Update

json
{
  "op": "db.update",
  "collection": "users",
  "data": {
    "_key": "user_123",
    "name": "Jane Doe",
    "score:$incr": 50,
    "tags:$push": "premium",
    "last_login:$now": true
  }
}

Insert with Calculations

json
{
  "op": "db.insert",
  "collection": "orders",
  "data": {
    "order_id:$uuid4": true,
    "user_id": "user_123",
    "items": [{ "name": "Widget", "price": 29.99, "qty": 2 }],
    "$subtotal": "@sum(@map(items, 'price * qty'))",
    "tax": "?{{ subtotal * 0.08 }}",
    "total": "?{{ subtotal + tax }}",
    "created_at:$now": true
  }
}

Query with Output

json
{
  "op": "db.find",
  "collection": "users",
  "filter": { "status": "active" },
  "output": {
    "display_name": "{{ first_name }} {{ last_name }}",
    "$age": "age",
    "member_since": "{{ @formatdate(_created_at, 'YYYY') }}"
  }
}

Authentication

json
{
  "op": "auth.signup",
  "email": "user@example.com",
  "password": "SecurePass123",
  "display_name": "John Doe"
}

File Upload

json
{
  "op": "file.presign_upload",
  "filename": "photo.jpg",
  "content_type": "image/jpeg",
  "public_read": true
}
json
{
  "op": "vdb.search",
  "query": "machine learning tutorials",
  "collection": "knowledge_base"
}

AI Text

json
{
  "op": "baseai.create",
  "input": "Write a product description for wireless headphones",
  "content_length": 200
}

Quick Reference

Structure:

json
{
  "op": "operation",
  "collection": "name",
  "filter": { "field:$operator": "value" },
  "data": { "field:$operator": "value" },
  "output": { "$field": "expression" },
  "sort": "field asc|desc",
  "limit": 50
}

Operators:

  • Filter: :$gt, :$gte, :$lt, :$lte, :$eq, :$ne, :$in, :$nin, :$between, :$includes, :$all, :$any, $or, $nor
  • Data: :$incr, :$decr, :$push, :$lpush, :$pop, :$lpop, :$extend, :$lextend, :$addset, :$remove, :$clear, :$now, :$timestamp, :$uuid, :$uuid4, :$uuid7

Expressions:

  • {{ expr }} - String
  • ?{{ expr }} - Native type
  • $field - Shorthand
  • @function() - Helpers

APIs:

  • db.* - Database operations
  • auth.* - Authentication
  • file.* - File storage
  • vdb.* - Vector search
  • baseai.* - AI text processing

BaseQL vs MongoDB

For developers familiar with MongoDB:

Query

MongoDB:

js
db.users.find({ 
  age: { $gte: 18 },
  status: { $in: ["active", "premium"] }
})

BaseQL:

json
{
  "op": "db.find",
  "collection": "users",
  "filter": {
    "age:$gte": 18,
    "status:$in": ["active", "premium"]
  }
}

Update

MongoDB:

js
db.users.updateOne(
  { _id: "user_123" },
  { 
    $set: { name: "Jane" },
    $inc: { score: 10 },
    $push: { tags: "premium" }
  }
)

BaseQL:

json
{
  "op": "db.update",
  "collection": "users",
  "filter": { "_key": "user_123" },
  "data": {
    "name": "Jane",
    "score:$incr": 10,
    "tags:$push": "premium"
  }
}

Aggregation

MongoDB:

js
db.orders.aggregate([
  { $match: { status: "completed" } },
  {
    $project: {
      total: { $multiply: ["$price", "$quantity"] },
      displayName: { $concat: ["$firstName", " ", "$lastName"] }
    }
  }
])

BaseQL:

json
{
  "op": "db.find",
  "collection": "orders",
  "filter": { "status": "completed" },
  "output": {
    "total": "?{{ price * quantity }}",
    "display_name": "{{ first_name }} {{ last_name }}"
  }
}

or with $

json
{
  "op": "db.find",
  "collection": "orders",
  "filter": { "status": "completed" },
  "output": {
    "$total": "price * quantity",
    "display_name": "{{ first_name }} {{ last_name }}"
  }
}

Complex Query

MongoDB:

js
db.products.find({
  price: { $gte: 10, $lte: 100 },
  category: { $in: ["electronics", "gadgets"] },
  stock: { $gt: 0 }
}).sort({ price: 1 }).limit(20)

BaseQL:

json
{
  "op": "db.find",
  "collection": "products",
  "filter": {
    "price:$between": [10, 100],
    "category:$in": ["electronics", "gadgets"],
    "stock:$gt": 0
  },
  "sort": "price asc",
  "limit": 20
}

Complex Update

MongoDB:

js
db.users.updateOne(
  { _id: "user_123" },
  {
    $set: { name: "Jane Doe", status: "active" },
    $inc: { score: 50, login_count: 1 },
    $push: { tags: "premium" },
    $currentDate: { last_login: true }
  }
)

BaseQL:

json
{
  "op": "db.update",
  "collection": "users",
  "filter": { "_key": "user_123" },
  "data": {
    "name": "Jane Doe",
    "status": "active",
    "score:$incr": 50,
    "login_count:$incr": 1,
    "tags:$push": "premium",
    "last_login:$now": true
  }
}

Projection

MongoDB:

js
db.orders.aggregate([
  { $match: { status: "completed" } },
  {
    $project: {
      orderId: "$_id",
      displayTotal: { $concat: ["$", { $toString: "$total" }] },
      itemCount: { $size: "$items" }
    }
  }
])

BaseQL:

json
{
  "op": "db.find",
  "collection": "orders",
  "filter": { "status": "completed" },
  "output": {
    "$order_id": "_key",
    "display_total": "${{ total }} USD",
    "$item_count": "@len(items)"
  }
}

Insert with Calculations

MongoDB:

js
// Requires separate calculation, then insert
const subtotal = items.reduce((sum, i) => sum + (i.price * i.qty), 0);
const tax = subtotal * 0.08;
const total = subtotal + tax;

db.orders.insertOne({
  order_id: new UUID(),
  user_id: "user_123",
  items: items,
  subtotal: subtotal,
  tax: tax,
  total: total,
  created_at: new Date()
});

BaseQL:

json
{
  "op": "db.insert",
  "collection": "orders",
  "data": {
    "order_id:$uuid4": true,
    "user_id": "user_123",
    "items": [{ "name": "Widget", "price": 29.99, "qty": 2 }],
    "$subtotal": "@sum(@map(items, 'price * qty'))",
    "tax": "?{{ subtotal * 0.08 }}",
    "total": "?{{ subtotal + tax }}",
    "created_at:$now": true
  }
}

Sorting

MongoDB:

js
db.products.find().sort({ category: 1, price: -1 })

BaseQL:

json
{
  "op": "db.find",
  "collection": "products",
  "sort": "category asc, price desc"
}

Joins

MongoDB:

js
db.orders.aggregate([
  {
    $lookup: {
      from: "users",
      localField: "user_id",
      foreignField: "_id",
      as: "user"
    }
  }
])

BaseQL:

json
{
  "op": "db.find",
  "collection": "orders",
  "lookup": {
    "user": {
      "collection": "users",
      "on": "user_key"
    }
  }
}

Key advantages:

  • Same familiar operators ($gte, $in, $push, etc.)
  • Cleaner inline syntax - no nested structures
  • Works across DB + Auth + Files + AI + Vector
  • Expressions replace complex aggregation pipelines
  • One operation does it all - no separate calculation steps
  • Simpler to read and write

Learn More