ArangoDB Queries Cheat Sheet

Introduction to ArangoDB Query Language

ArangoDB Query Language (AQL) is the primary query language for ArangoDB, a multi-model NoSQL database system that supports document, graph, and key-value data models. AQL allows you to retrieve, manipulate, and transform data stored in ArangoDB using a syntax similar to SQL but optimized for working with documents and graphs. Mastering AQL is essential for efficiently working with ArangoDB and leveraging its full power across different data models.

Core AQL Concepts

Basic Structure of an AQL Query

FOR variable IN collection
    FILTER condition
    SORT variable.attribute DIRECTION
    LIMIT offset, count
    RETURN projection

Data Types in AQL

TypeDescriptionExample
NullNull valuenull
BooleanTrue or falsetrue, false
NumberNumeric values42, 3.14159
StringText values"Hello", 'World'
ArrayOrdered list[1, 2, 3]
ObjectDocument/object{ "name": "John" }

Document Queries

Basic Data Retrieval

// Retrieve all documents from a collection
FOR doc IN users
    RETURN doc

// Retrieve specific fields
FOR doc IN users
    RETURN { name: doc.name, email: doc.email }

Filtering Data

// Basic filter
FOR doc IN users
    FILTER doc.age >= 18
    RETURN doc

// Multiple conditions
FOR doc IN users
    FILTER doc.age >= 18 AND doc.status == "active"
    RETURN doc

// OR condition
FOR doc IN users
    FILTER doc.country == "USA" OR doc.country == "Canada"
    RETURN doc

// Existence check
FOR doc IN users
    FILTER doc.email != null
    RETURN doc

Sorting Results

// Single attribute ascending
FOR doc IN users
    SORT doc.name ASC
    RETURN doc

// Multiple attributes
FOR doc IN users
    SORT doc.age DESC, doc.name ASC
    RETURN doc

Limiting Results

// First 10 results
FOR doc IN users
    LIMIT 10
    RETURN doc

// Skip 20, take 10 (pagination)
FOR doc IN users
    LIMIT 20, 10
    RETURN doc

Graph Queries

Traversing Graphs

// Basic traversal
FOR vertex, edge, path IN 1..3 OUTBOUND 'users/john' friendships
    RETURN vertex

// With filtering
FOR vertex, edge, path IN 1..3 OUTBOUND 'users/john' friendships
    FILTER vertex.age > 30
    RETURN vertex

Shortest Path

FOR path IN OUTBOUND SHORTEST_PATH 'users/john' TO 'users/jane' friendships
    RETURN path

All Paths

FOR path IN OUTBOUND ANY_SHORTEST_PATH 'users/john' TO 'users/jane' friendships
    RETURN path

Advanced Techniques

Joins

// Joining collections
FOR user IN users
    FOR order IN orders
        FILTER order.user_id == user._key
        RETURN { user: user.name, order: order.id }

Aggregations

// Count
RETURN COUNT(
    FOR doc IN users
        FILTER doc.active == true
        RETURN 1
)

// Group by with aggregation
FOR doc IN sales
    COLLECT category = doc.category WITH COUNT INTO count
    RETURN { category, count }

// Complex aggregation
FOR doc IN orders
    COLLECT region = doc.region, year = DATE_YEAR(doc.date)
    AGGREGATE total = SUM(doc.amount)
    RETURN { region, year, total }

Subqueries

FOR user IN users
    LET userOrders = (
        FOR order IN orders
            FILTER order.user_id == user._id
            RETURN order
    )
    RETURN { user: user.name, orders: userOrders }

Data Manipulation

Insert Operations

// Insert single document
INSERT { 
    name: "John", 
    email: "john@example.com" 
} INTO users

// Insert multiple documents
FOR user IN [
    { name: "Alice", email: "alice@example.com" },
    { name: "Bob", email: "bob@example.com" }
]
    INSERT user INTO users

Update Operations

// Update single document
UPDATE "12345" WITH { 
    status: "inactive" 
} IN users

// Update multiple documents
FOR user IN users
    FILTER user.age < 18
    UPDATE user WITH { 
        minor: true 
    } IN users

Replace Operations

// Replace document (overwrites entire document)
REPLACE "12345" WITH {
    name: "John Doe",
    email: "john@example.com",
    age: 35
} IN users

Remove Operations

// Remove single document
REMOVE "12345" IN users

// Remove multiple documents
FOR user IN users
    FILTER user.status == "deleted"
    REMOVE user IN users

Upsert Operations

// Insert if not exists, update if exists
UPSERT { name: "John" }
    INSERT { name: "John", created: DATE_NOW() }
    UPDATE { updated: DATE_NOW() }
    IN users

Common Functions

String Functions

FunctionDescriptionExample
CONCAT()Concatenate stringsCONCAT("Hello", " ", "World")
LOWER()Convert to lowercaseLOWER("TEXT")
UPPER()Convert to uppercaseUPPER("text")
SUBSTRING()Extract substringSUBSTRING("abcdef", 1, 3)
CONTAINS()Check if string containsCONTAINS("abc", "b")
LENGTH()String lengthLENGTH("text")

Numeric Functions

FunctionDescriptionExample
ABS()Absolute valueABS(-5)
CEIL()Round upCEIL(3.4)
FLOOR()Round downFLOOR(3.7)
ROUND()Round to nearestROUND(3.5)
RAND()Random numberRAND()
MAX()Maximum valueMAX(2, 3, 1)
MIN()Minimum valueMIN(2, 3, 1)

Date Functions

FunctionDescriptionExample
DATE_NOW()Current date/timeDATE_NOW()
DATE_ISO8601()Format as ISO8601DATE_ISO8601(DATE_NOW())
DATE_YEAR()Extract yearDATE_YEAR(DATE_NOW())
DATE_MONTH()Extract monthDATE_MONTH(DATE_NOW())
DATE_DAY()Extract dayDATE_DAY(DATE_NOW())

Common Challenges and Solutions

Performance Optimization

ChallengeSolution
Slow queriesCreate indexes on frequently filtered fields
Large result setsUse LIMIT and pagination
Complex joinsConsider denormalizing data or using graph relationships
Slow aggregationsUse indexed fields for aggregation keys

Working with Indexes

// Create index
db.users.ensureIndex({ type: "hash", fields: ["email"] })

// Create composite index
db.users.ensureIndex({ type: "hash", fields: ["country", "city"] })

// Create geo index
db.locations.ensureIndex({ type: "geo", fields: ["coordinates"] })

// Create fulltext index
db.products.ensureIndex({ type: "fulltext", fields: ["description"] })

Error Handling

// Try-catch in AQL
TRY
    FOR doc IN collection
        RETURN doc
CATCH
    RETURN { error: true, message: "An error occurred" }

Best Practices

Query Optimization

  • Always use indexes for filtered fields
  • Limit result sets to necessary documents
  • Avoid large in-memory operations
  • Use bind parameters for dynamic values
  • Monitor query execution plans with EXPLAIN

Data Modeling

  • Choose appropriate collection types (document vs. edge)
  • Consider embedding related data for frequently joined information
  • Use graph relationships for complex connections
  • Keep document size manageable (< 64MB)
  • Use sensible _key values for better performance

Security Considerations

  • Always validate and sanitize user input
  • Use bind parameters to prevent injection attacks
  • Apply proper access controls at collection level
  • Avoid exposing internal document IDs to users
  • Use ArangoDB’s security features (roles, permissions)

AQL vs SQL Comparison

SQLAQLNotes
SELECT * FROM usersFOR u IN users RETURN uBasic retrieval
SELECT * FROM users WHERE age >= 18FOR u IN users FILTER u.age >= 18 RETURN uFiltering
SELECT * FROM users ORDER BY name ASCFOR u IN users SORT u.name ASC RETURN uSorting
SELECT * FROM users LIMIT 10FOR u IN users LIMIT 10 RETURN uLimiting
SELECT u.name, o.id FROM users u JOIN orders o ON u.id = o.user_idFOR u IN users FOR o IN orders FILTER o.user_id == u._key RETURN {name: u.name, order: o.id}Joins
SELECT COUNT(*) FROM usersRETURN LENGTH(users)Count
INSERT INTO users VALUES ('John', 'john@ex.com')INSERT {name: "John", email: "john@ex.com"} INTO usersInsert
UPDATE users SET status = 1 WHERE id = 123UPDATE "123" WITH {status: 1} IN usersUpdate
DELETE FROM users WHERE id = 123REMOVE "123" IN usersDelete

Resources for Further Learning

Official Documentation

Learning Resources

Community Resources

Tools

Remember that ArangoDB’s multi-model approach allows you to combine document, graph, and key-value operations in a single query, providing exceptional flexibility and power for complex data operations.

Scroll to Top