Skip to content

DocumentDB Interface Guide

This guide describes how to use the DocumentDb interface to interact with AWS DocumentDB (or MongoDB-compatible databases).

Initialization

The interface automatically loads credentials from navconfig (environment variables).

from parrot.interfaces.documentdb import DocumentDb

db = DocumentDb()
# Connection is lazy, but you can explicitly connect:
await db.documentdb_connect()

Creating Buckets and Collections

In DocumentDB/MongoDB, databases and collections are typically created on the first write. However, you can explicitly create them to set options or ensure existence.

# Create a collection with specific options (implicit creation or explicit validation)
await db.create_collection("conversations")

# Create a 'bucket' (GridFS bucket or logical grouping)
# This usually ensures the necessary GridFS collections (chunks/files) exist.
await db.create_bucket("conversation_attachments")

Indexing

You can improve query performance by indexing specific fields.

Example: Indexing conversations by session_id and turn_id

# Create a compound index on session_id (ascending) and turn_id (ascending)
# 1 = Ascending, -1 = Descending
keys = [
    ("session_id", 1),
    ("turn_id", 1)
]

await db.create_indexes("conversations", keys)

Streaming Data

When dealing with large datasets (e.g., retrieving all turns of a long conversation), use streaming to process items without loading everything into memory.

Streaming Items (Iterate)

Process documents one by one as they are retrieved from the database cursor.

collection = "conversations"
query = {"session_id": "12345-abcde"}

# 'iterate' (or 'read_batch') yields individual documents
async for turn in db.iterate(collection, query):
    print(f"Processing turn {turn['turn_id']}")
    # process_turn(turn)

Streaming Batches (Chunked)

Process documents in chunks (lists) of a specific size. Useful for bulk API processing.

# 'read_chunks' yields lists of documents
async for batch in db.read_chunks(collection, query, chunk_size=50):
    print(f"Sending batch of {len(batch)} turns to analytics...")
    # await send_to_analytics(batch)

Background Saving (Fire-and-Forget)

Use save_background to write data without blocking the main execution flow. The save operation runs as a background asyncio task.

data = {
    "session_id": "12345-abcde",
    "turn_id": 1,
    "user_input": "Hello",
    "timestamp": "2023-10-27T10:00:00Z"
}

# Returns immediately; save happens in background
db.save_background("conversations", data)

print("Turn processed, saving in background...")

Full Example

import asyncio
from parrot.interfaces.documentdb import DocumentDb

async def main():
    db = DocumentDb()

    # 1. Setup Collection & Index
    await db.create_collection("conversations")
    await db.create_indexes("conversations", [("session_id", 1), ("turn_id", 1)])

    # 2. Fire-and-forget save
    turn_data = {"session_id": "sess-01", "turn_id": 10, "content": "Hi"}
    db.save_background("conversations", turn_data)

    # 3. Stream back data
    async for turn in db.iterate("conversations", {"session_id": "sess-01"}):
        print("Read turn:", turn)

if __name__ == "__main__":
    asyncio.run(main())