Documents Guide
Documents are the individual records stored within collections. They contain your actual data and can be created, read, updated, and deleted using the CocoBase client.
📄 What are Documents?
Documents are JSON-like objects that store your data. Think of them as:
- Rows in SQL databases
 - Documents in NoSQL databases
 - Records in your application
 
Each document has:
- A unique ID (auto-generated)
 - A collection ID (which collection it belongs to)
 - Data (your actual content)
 - A creation timestamp
 - Collection metadata
 
🆕 Creating Documents
Basic Document Creation
from cocobase_client import CocoBaseClient
client = CocoBaseClient(api_key="your_api_key")
# First, create or get a collection
collection = client.create_collection("users")
# Create a document
user_data = {
    "name": "John Doe",
    "email": "john@example.com",
    "age": 30,
    "active": True
}
user = client.create_document(collection.id, user_data)
if user:
    print(f"Created user: {user['name']}")
    print(f"Document ID: {user.id}")
    print(f"Created at: {user.createdAt}")
Complex Document Creation
# Create a more complex document with nested data
product_data = {
    "name": "Laptop",
    "description": "High-performance laptop for developers",
    "price": 1299.99,
    "category": "Electronics",
    "specifications": {
        "ram": "16GB",
        "storage": "512GB SSD",
        "processor": "Intel i7"
    },
    "tags": ["laptop", "computer", "electronics"],
    "in_stock": True,
    "quantity": 25
}
product = client.create_document(collection.id, product_data)
📖 Reading Documents
Get Single Document
# Retrieve a specific document by ID
document = client.get_document(
    collection_id="your_collection_id",
    document_id="your_document_id"
)
if document:
    print(f"Document ID: {document.id}")
    print(f"Data: {document.data}")
    # Access specific fields
    print(f"Name: {document['name']}")
    print(f"Email: {document.get('email', 'No email')}")
List All Documents
# Get all documents in a collection
documents = client.list_documents(collection_id="your_collection_id")
if documents:
    print(f"Found {len(documents)} documents")
    for doc in documents:
        print(f"- {doc['name']}: {doc['email']}")
List Documents with Query
from cocobase_client.query import QueryBuilder
# Build a query to filter documents
query = QueryBuilder().eq("active", True).gt("age", 18).limit(10)
# Get filtered documents
active_adults = client.list_documents(
    collection_id="your_collection_id",
    query=query
)
if active_adults:
    print(f"Found {len(active_adults)} active adults")
🔄 Updating Documents
Full Document Update
# Update a document with new data
updated_data = {
    "name": "John Smith",  # Updated name
    "email": "john.smith@example.com",  # Updated email
    "age": 31,  # Updated age
    "active": True,
    "last_login": "2024-01-15T10:30:00Z"
}
updated_document = client.update_document(
    collection_id="your_collection_id",
    document_id="your_document_id",
    data=updated_data
)
if updated_document:
    print(f"Updated document: {updated_document['name']}")
Partial Document Update
# Update only specific fields
partial_update = {
    "last_login": "2024-01-15T14:45:00Z",
    "login_count": 15
}
updated_document = client.update_document(
    collection_id="your_collection_id",
    document_id="your_document_id",
    data=partial_update
)
🗑️ Deleting Documents
# Delete a document
success = client.delete_document(
    collection_id="your_collection_id",
    document_id="your_document_id"
)
if success:
    print("Document deleted successfully")
else:
    print("Failed to delete document")
📊 Working with Record Objects
When you retrieve documents, you get Record objects with helpful methods:
Basic Record Access
# Get a document
user = client.get_document(collection_id, document_id)
# Dictionary-like access
name = user['name']
email = user.get('email', 'No email provided')
# Direct property access
print(f"Document ID: {user.id}")
print(f"Collection ID: {user.collectionId}")
print(f"Created at: {user.createdAt}")
Type-Safe Getters
# Use type-safe getters to ensure data types
user = client.get_document(collection_id, document_id)
# Get values with automatic type conversion
name = user.get_string('name')  # Returns string or None
age = user.get_int('age')       # Returns int or None
active = user.get_bool('active') # Returns bool or None
price = user.get_float('price') # Returns float or None
created = user.get_datetime('created_at') # Returns datetime or None
# With error handling
try:
    age = user.get_int('age', raise_error=True)
    print(f"User age: {age}")
except TypeError as e:
    print(f"Invalid age value: {e}")
🔍 Advanced Querying
Complex Queries
from cocobase_client.query import QueryBuilder
# Build complex queries
query = (QueryBuilder()
         .eq('category', 'Electronics')
         .gte('price', 100)
         .lt('price', 1000)
         .contains('name', 'laptop')
         .limit(20)
         .offset(0))
products = client.list_documents(collection_id, query)
Pagination
def get_all_documents_paginated(client, collection_id, page_size=50):
    """Get all documents with pagination"""
    offset = 0
    all_documents = []
    while True:
        query = QueryBuilder().limit(page_size).offset(offset)
        documents = client.list_documents(collection_id, query)
        if not documents:
            break
        all_documents.extend(documents)
        if len(documents) < page_size:
            break
        offset += page_size
    return all_documents
🛠️ Error Handling
from cocobase_client.exceptions import CocobaseError
try:
    # Attempt to create a document
    document = client.create_document(collection_id, document_data)
    print(f"Document created: {document.id}")
except CocobaseError as e:
    if "Invalid Request" in str(e):
        print("Invalid data or collection ID")
    elif "field is missing" in str(e):
        print("Required field missing")
    elif "Internal Server Error" in str(e):
        print("Server error occurred")
    else:
        print(f"API error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")
📝 Complete CRUD Example
from cocobase_client import CocoBaseClient
from cocobase_client.query import QueryBuilder
from cocobase_client.exceptions import CocobaseError
class DocumentManager:
    def __init__(self, api_key: str, collection_id: str):
        self.client = CocoBaseClient(api_key=api_key)
        self.collection_id = collection_id
    def create_user(self, name: str, email: str, age: int):
        """Create a new user document"""
        user_data = {
            "name": name,
            "email": email,
            "age": age,
            "active": True,
            "created_at": "2024-01-01T12:00:00Z"
        }
        try:
            user = self.client.create_document(self.collection_id, user_data)
            print(f"✅ Created user: {user['name']} (ID: {user.id})")
            return user
        except CocobaseError as e:
            print(f"❌ Failed to create user: {e}")
            return None
    def get_user(self, user_id: str):
        """Get a user by ID"""
        try:
            user = self.client.get_document(self.collection_id, user_id)
            if user:
                print(f"Found user: {user['name']} ({user['email']})")
                return user
            else:
                print("User not found")
                return None
        except CocobaseError as e:
            print(f"❌ Error getting user: {e}")
            return None
    def update_user(self, user_id: str, updates: dict):
        """Update a user document"""
        try:
            updated_user = self.client.update_document(
                self.collection_id, user_id, updates
            )
            if updated_user:
                print(f"✅ Updated user: {updated_user['name']}")
                return updated_user
            else:
                print("Failed to update user")
                return None
        except CocobaseError as e:
            print(f"❌ Error updating user: {e}")
            return None
    def delete_user(self, user_id: str):
        """Delete a user document"""
        try:
            success = self.client.delete_document(self.collection_id, user_id)
            if success:
                print("✅ User deleted successfully")
                return True
            else:
                print("❌ Failed to delete user")
                return False
        except CocobaseError as e:
            print(f"❌ Error deleting user: {e}")
            return False
    def search_users(self, name_contains: str = None, min_age: int = None):
        """Search for users with filters"""
        query = QueryBuilder()
        if name_contains:
            query.contains('name', name_contains)
        if min_age:
            query.gte('age', min_age)
        query.limit(100)  # Limit results
        try:
            users = self.client.list_documents(self.collection_id, query)
            print(f"Found {len(users)} users matching criteria")
            return users
        except CocobaseError as e:
            print(f"❌ Error searching users: {e}")
            return []
    def get_user_stats(self):
        """Get statistics about users"""
        try:
            all_users = self.client.list_documents(self.collection_id)
            if not all_users:
                return {"total": 0, "active": 0, "average_age": 0}
            total_users = len(all_users)
            active_users = sum(1 for user in all_users if user.get('active', False))
            # Calculate average age
            ages = [user.get_int('age') for user in all_users if user.get_int('age')]
            average_age = sum(ages) / len(ages) if ages else 0
            stats = {
                "total": total_users,
                "active": active_users,
                "inactive": total_users - active_users,
                "average_age": round(average_age, 1)
            }
            print(f"📊 User Stats: {stats}")
            return stats
        except CocobaseError as e:
            print(f"❌ Error getting user stats: {e}")
            return {}
# Usage Example
def main():
    # Initialize the document manager
    manager = DocumentManager("your_api_key", "your_collection_id")
    # Create users
    user1 = manager.create_user("Alice Smith", "alice@example.com", 28)
    user2 = manager.create_user("Bob Johnson", "bob@example.com", 35)
    if user1:
        # Update user
        manager.update_user(user1.id, {"last_login": "2024-01-15T10:30:00Z"})
        # Get user
        retrieved_user = manager.get_user(user1.id)
        # Search users
        young_users = manager.search_users(min_age=25)
        # Get statistics
        stats = manager.get_user_stats()
        # Delete user (commented out to preserve data)
        # manager.delete_user(user1.id)
if __name__ == "__main__":
    main()
🚀 Advanced Document Patterns
Batch Operations
def create_users_batch(client, collection_id, users_data):
    """Create multiple users in batch"""
    created_users = []
    failed_users = []
    for user_data in users_data:
        try:
            user = client.create_document(collection_id, user_data)
            created_users.append(user)
            print(f"✅ Created: {user['name']}")
        except CocobaseError as e:
            failed_users.append({"data": user_data, "error": str(e)})
            print(f"❌ Failed to create {user_data.get('name', 'Unknown')}: {e}")
    return created_users, failed_users
# Usage
users_to_create = [
    {"name": "User 1", "email": "user1@example.com", "age": 25},
    {"name": "User 2", "email": "user2@example.com", "age": 30},
    {"name": "User 3", "email": "user3@example.com", "age": 35},
]
created, failed = create_users_batch(client, collection_id, users_to_create)
Document Validation
def validate_user_data(data):
    """Validate user data before creating/updating"""
    errors = []
    # Required fields
    if not data.get('name'):
        errors.append("Name is required")
    if not data.get('email'):
        errors.append("Email is required")
    # Email format validation
    if data.get('email') and '@' not in data['email']:
        errors.append("Invalid email format")
    # Age validation
    age = data.get('age')
    if age is not None:
        if not isinstance(age, int) or age < 0 or age > 150:
            errors.append("Age must be a valid number between 0 and 150")
    return errors
def create_user_with_validation(client, collection_id, user_data):
    """Create user with validation"""
    errors = validate_user_data(user_data)
    if errors:
        print(f"❌ Validation errors: {', '.join(errors)}")
        return None
    try:
        user = client.create_document(collection_id, user_data)
        print(f"✅ Created validated user: {user['name']}")
        return user
    except CocobaseError as e:
        print(f"❌ Failed to create user: {e}")
        return None
Document Relationships
def create_order_with_user(client, users_collection_id, orders_collection_id,
                          user_id, order_data):
    """Create an order linked to a user"""
    # First verify the user exists
    user = client.get_document(users_collection_id, user_id)
    if not user:
        print("❌ User not found")
        return None
    # Add user reference to order
    order_data['user_id'] = user_id
    order_data['user_name'] = user['name']
    order_data['user_email'] = user['email']
    # Create the order
    try:
        order = client.create_document(orders_collection_id, order_data)
        print(f"✅ Created order {order.id} for user {user['name']}")
        return order
    except CocobaseError as e:
        print(f"❌ Failed to create order: {e}")
        return None
def get_user_orders(client, orders_collection_id, user_id):
    """Get all orders for a specific user"""
    query = QueryBuilder().eq('user_id', user_id)
    try:
        orders = client.list_documents(orders_collection_id, query)
        print(f"Found {len(orders)} orders for user {user_id}")
        return orders
    except CocobaseError as e:
        print(f"❌ Error getting user orders: {e}")
        return []
🔧 Performance Tips
Efficient Querying
# ✅ Good: Use specific queries to limit results
query = QueryBuilder().eq('category', 'Electronics').limit(50)
products = client.list_documents(collection_id, query)
# ❌ Avoid: Getting all documents when you only need a few
all_products = client.list_documents(collection_id)  # Could be thousands!
Selective Field Updates
# ✅ Good: Update only changed fields
updates = {"last_login": "2024-01-15T10:30:00Z"}
client.update_document(collection_id, document_id, updates)
# ❌ Avoid: Sending entire document for small changes
# This wastes bandwidth and may overwrite concurrent changes
Batch Processing
def process_documents_in_batches(client, collection_id, batch_size=100):
    """Process documents in batches to avoid memory issues"""
    offset = 0
    while True:
        query = QueryBuilder().limit(batch_size).offset(offset)
        documents = client.list_documents(collection_id, query)
        if not documents:
            break
        # Process this batch
        for doc in documents:
            # Your processing logic here
            process_document(doc)
        print(f"Processed {len(documents)} documents")
        if len(documents) < batch_size:
            break
        offset += batch_size
📈 Document Monitoring
Track Document Changes
def track_document_changes(client, collection_id, document_id):
    """Track when a document was last modified"""
    document = client.get_document(collection_id, document_id)
    if document:
        # Add tracking metadata
        updates = {
            "last_modified": "2024-01-15T12:00:00Z",
            "modified_by": "system",
            "version": document.get('version', 0) + 1
        }
        updated = client.update_document(collection_id, document_id, updates)
        return updated
    return None
Next Steps:
- Query Builder Guide - Master complex queries
 - Record Class Guide - Learn about type-safe data access
 - Authentication Guide - Secure