Skip to content

# Transactions

### Use Case 3: Transaction Support for Multi-Document Operations

Scenario: Order processing system that updates inventory and creates order atomically.

Python

    from mongo_ops import BaseDocument, BaseRepository, TransactionManager
    from datetime import datetime
    from typing import List
    from pydantic import Field

    class Order(BaseDocument):
        user_id: str
        items: List[dict]  # [{"product_id": "...", "quantity": 2}]
        total_amount: float
        status: str = "pending"

    class OrderRepository(BaseRepository[Order]):
        def __init__(self):
            super().__init__("orders", Order)

    class OrderService:
        def __init__(self, order_repo: OrderRepository, product_repo: ProductRepository):
            self.order_repo = order_repo
            self.product_repo = product_repo

        async def create_order_with_inventory_update(self, order: Order) -> Order:
            """Create order and update inventory atomically"""

            async def create_order_transaction(session):
                # Insert order
                order_doc = order.model_dump(exclude={"id"}, exclude_none=True)
                order_doc["created_at"] = datetime.utcnow()
                order_doc["updated_at"] = datetime.utcnow()
                result = await self.order_repo.collection.insert_one(order_doc, session=session)

                # Update inventory for each item
                for item in order.items:
                    await self.product_repo.collection.update_one(
                        {"_id": ObjectId(item["product_id"])},
                        {
                            "$inc": {"quantity": -item["quantity"]},
                            "$set": {"updated_at": datetime.utcnow()}
                        },
                        session=session
                    )

                # Fetch created order
                created = await self.order_repo.collection.find_one(
                    {"_id": result.inserted_id},
                    session=session
                )
                return Order(**created)

            # Execute in transaction
            async with TransactionManager.start_session() as session:
                return await create_order_transaction(session)

    # Usage in FastAPI
    @app.post("/orders/", response_model=Order)
    async def create_order(order: Order):
        order_service = OrderService(order_repo, product_repo)
        try:
            return await order_service.create_order_with_inventory_update(order)
        except Exception as e:
            raise HTTPException(status_code=400, detail=str(e))