Skip to content

Need session storage for NoSQL DB #4834

Closed
Closed

Description

@Vasanthan88

Hi Team,

I do have Mongo DB and I would like to save sessions events in the MongoDb and need to retrieve, update and delete the sessions.

Currently session storage is only available in relational DB.

Can I store and retrieve sessions using Mongo. If so can you please provide a sample code in python.

Thanks,
Vasanth

Activity

  1. added
    services[Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc
    on Mar 14, 2026
  2. added theissue type on Mar 14, 2026
  3. klateefa commented on Mar 16, 2026

    @klateefa

    @Vasanthan88 Thanks for opening this request. Could you please share more information about your use case? It will help us understand your request better.
    Thank you

  4. self-assigned this
    on Mar 16, 2026
  5. added
    request clarification[Status] The maintainer need clarification or more information from the author
    on Mar 16, 2026
  6. Vasanthan88 commented on Mar 16, 2026

    @Vasanthan88
    Author

    @klateefa : I have a mongo DB and I need to store the session using DatabaseSessionService. I need to use mongo DB instead of regular relational database

    Something like DatabaseSessionService(Mongo_DB_URL) so that all the sessions, events,app are stored in the Mongo DB and it can be retrieved, created, deleted using default goolge adk api's.

  7. JesserHamdaoui commented on Mar 17, 2026

    @JesserHamdaoui
    Contributor

    @klateefa

    I believe this feature is not implemented yet, from what I can see DatabaseSessionService currently supports SQLite, PostgreSQL and MySQL via SQLAlchemy. Please correct me if I'm wrong.

    If adding a MongoDBSessionService aligns with your vision I would be happy to contribute, if so please assign the issue to me and I will start working on it.

    Based on what I noticed from the source code, this is the approach I would take:

    • Subclass BaseSessionService and implement all 5 required methods (create_session, get_session, list_sessions, delete_session, append_event) using motor, the official async MongoDB Python driver.
    • Use two collections: sessions for metadata and state, and events for event JSON indexed by app_name, user_id, session_id and timestamp.
    • In append_event, call the existing base helpers _trim_temp_delta_state and _update_session_state to stay consistent with how other session services handle state deltas, then persist the event and update the session document.

    Happy to discuss any design decisions before starting.

  8. InfernalAzazel commented on Mar 23, 2026

    @InfernalAzazel

    @klateefa

    I believe this feature is not implemented yet, from what I can see DatabaseSessionService currently supports SQLite, PostgreSQL and MySQL via SQLAlchemy. Please correct me if I'm wrong.

    If adding a MongoDBSessionService aligns with your vision I would be happy to contribute, if so please assign the issue to me and I will start working on it.

    Based on what I noticed from the source code, this is the approach I would take:

    • Subclass BaseSessionService and implement all 5 required methods (create_session, get_session, list_sessions, delete_session, append_event) using motor, the official async MongoDB Python driver.
    • Use two collections: sessions for metadata and state, and events for event JSON indexed by app_name, user_id, session_id and timestamp.
    • In append_event, call the existing base helpers _trim_temp_delta_state and _update_session_state to stay consistent with how other session services handle state deltas, then persist the event and update the session document.

    Happy to discuss any design decisions before starting.

    The motor will no longer be maintained in a few months, and you can use the official import from Pymongo to Asynchronous MongoClient

  9. InfernalAzazel commented on Mar 23, 2026

    @InfernalAzazel

    Temporary use, waiting for official implementation

    """MongoDB session service implementation for Google ADK."""
    
    import copy
    import time
    import uuid
    from typing import Any, Optional
    
    from pymongo import AsyncMongoClient
    from google.adk.events.event import Event
    from google.adk.sessions.base_session_service import (
        BaseSessionService,
        GetSessionConfig,
        ListSessionsResponse,
    )
    from google.adk.sessions.session import Session
    from google.adk.sessions.state import State
    
    
    class MongoSessionService(BaseSessionService):
    
        def __init__(self, mongo_url: str, db_name: Optional[str] = None, **kwargs: Any):
            client = AsyncMongoClient(mongo_url, **kwargs)
            self.db = client[db_name] if db_name else client.get_default_database()
            self.sessions = self.db.sessions
            self.events = self.db.events
            self.app_states = self.db.app_states
            self.user_states = self.db.user_states
    
        async def create_session(
            self,
            *,
            app_name: str,
            user_id: str,
            state: Optional[dict[str, Any]] = None,
            session_id: Optional[str] = None,
        ) -> Session:
            sid = session_id or uuid.uuid4().hex
            now = time.time()
            session_state = state or {}
    
            await self.sessions.insert_one(
                {
                    "app_name": app_name,
                    "user_id": user_id,
                    "id": sid,
                    "state": session_state,
                    "last_update_time": now,
                }
            )
    
            session = Session(
                id=sid,
                app_name=app_name,
                user_id=user_id,
                state=session_state,
                events=[],
                last_update_time=now,
            )
            return await self._merge_state(app_name, user_id, copy.deepcopy(session))
    
        async def get_session(
            self,
            *,
            app_name: str,
            user_id: str,
            session_id: str,
            config: Optional[GetSessionConfig] = None,
        ) -> Optional[Session]:
            filt = {"app_name": app_name, "user_id": user_id, "id": session_id}
            doc = await self.sessions.find_one(filt)
            if not doc:
                return None
    
            # Get all events for this session
            raw_events = (
                await self.events.find(filt).sort("timestamp", 1).to_list(length=None)
            )
            events = [Event.model_validate_json(e["raw"]) for e in raw_events]
    
            # Apply config filters if provided
            if config:
                if config.after_timestamp is not None:
                    events = [e for e in events if e.timestamp >= config.after_timestamp]
                if config.num_recent_events is not None and events:
                    events = events[-config.num_recent_events :]
    
            session = Session(
                id=session_id,
                app_name=app_name,
                user_id=user_id,
                state=doc.get("state", {}),
                events=events,
                last_update_time=doc.get("last_update_time", 0.0),
            )
    
            return await self._merge_state(app_name, user_id, copy.deepcopy(session))
    
        async def list_sessions(
            self, *, app_name: str, user_id: str
        ) -> ListSessionsResponse:
            cursor = self.sessions.find({"app_name": app_name, "user_id": user_id})
            sessions: list[Session] = []
            async for doc in cursor:
                sessions.append(
                    Session(
                        id=doc["id"],
                        app_name=app_name,
                        user_id=user_id,
                        state={},
                        events=[],
                        last_update_time=doc.get("last_update_time", 0.0),
                    )
                )
            return ListSessionsResponse(sessions=sessions)
    
        async def delete_session(
            self, *, app_name: str, user_id: str, session_id: str
        ) -> None:
            filt = {"app_name": app_name, "user_id": user_id, "id": session_id}
            await self.sessions.delete_one(filt)
            await self.events.delete_many(filt)
    
        async def _merge_state(
            self, app_name: str, user_id: str, session: Session
        ) -> Session:
            """Merge app and user state into the session."""
            # Merge app state
            app_states = await self.app_states.find({"app_name": app_name}).to_list(
                length=None
            )
            for state in app_states:
                session.state[State.APP_PREFIX + state["key"]] = state["value"]
    
            # Merge user state
            user_states = await self.user_states.find(
                {"app_name": app_name, "user_id": user_id}
            ).to_list(length=None)
            for state in user_states:
                session.state[State.USER_PREFIX + state["key"]] = state["value"]
    
            return session
    
        async def append_event(self, session: Session, event: Event) -> Event:
            if event.partial:
                return event
    
            filt = {
                "app_name": session.app_name,
                "user_id": session.user_id,
                "id": session.id,
            }
            doc = await self.sessions.find_one(filt)
            if not doc:
                raise ValueError("session not found")
    
            if doc.get("last_update_time", 0.0) > session.last_update_time:
                raise ValueError("stale session")
    
            new_event = await super().append_event(session=session, event=event)
    
            # Store the event
            await self.events.insert_one(
                {
                    **filt,
                    "raw": new_event.model_dump_json(),
                    "timestamp": new_event.timestamp,
                }
            )
    
            # Update session state and timestamp
            await self.sessions.update_one(
                filt,
                {
                    "$set": {
                        "state": session.state,
                        "last_update_time": session.last_update_time,
                    }
                },
            )
    
            # Process state deltas if present
            if event.actions and event.actions.state_delta:
                for key, value in event.actions.state_delta.items():
                    if key.startswith(State.APP_PREFIX):
                        # Update app state
                        app_key = key.removeprefix(State.APP_PREFIX)
                        await self.app_states.update_one(
                            {"app_name": session.app_name, "key": app_key},
                            {"$set": {"value": value}},
                            upsert=True,
                        )
    
                    elif key.startswith(State.USER_PREFIX):
                        # Update user state
                        user_key = key.removeprefix(State.USER_PREFIX)
                        await self.user_states.update_one(
                            {
                                "app_name": session.app_name,
                                "user_id": session.user_id,
                                "key": user_key,
                            },
                            {"$set": {"value": value}},
                            upsert=True,
                        )
    
            return new_event

    use

     session_service = MongoSessionService(mongo_url=config.mongo_db_url, db_name=config.mongo_db_name)
        runner = Runner(
            app_name="opencat",
            agent=root_agent,
            session_service=session_service,
            auto_create_session=True,
        )

    @Vasanthan88 This is a temporary solution in my project

  10. atandon2024 commented on Jun 28, 2026

    @atandon2024

    Hi! I just came across this issue and wanted to check in. Is there still interest in getting an official MongoDBSessionService into the codebase? @JesserHamdaoui mentioned being willing to contribute, has there been any movement on that? I'm also interested in helping out.

  11. JesserHamdaoui commented on Jul 1, 2026

    @JesserHamdaoui
    Contributor

    Hi @atandon2024
    Go ahead! I'd be happy to review and help if needed.

  12. adk-bot commented on Jul 21, 2026

    @adk-bot
    Collaborator

    🚨 Automated Spam Detection Alert 🚨
    @maintainers, a suspected spam comment was detected in this thread.

    Reason:

    @impeachmentright posted promotional spam offering services as a 'Live A2A contractor' with a link to an external website (https://a2a.elonsusk.com/).
    
  13. added
    spam[Status] Issues suspected of having comments which are spam
    on Jul 21, 2026
  14. removed
    spam[Status] Issues suspected of having comments which are spam
    on Oct 14, 2026
  15. DeanChensj commented on Oct 14, 2026

    @DeanChensj
    Collaborator

    Thanks everyone for the interest and discussion here! Quick update: we currently have an official MongoDB session integration ongoing and support for it will be landing soon. Stay tuned!

  16. self-assigned this
    on Oct 26, 2026
  17. GWeale commented on Oct 26, 2026

    @GWeale
    Collaborator

    hi @Vasanthan88, thanks for asking for this, and thanks to everyone who weighed in on the thread. mongodb session storage landed in 9833835 (#7511, with thanks to @theshanbhag for building it) and shipped in 2.13.0. you can install it with pip install 'google-adk[mongodb]' and use MongoDbSessionService from google.adk.integrations.mongodb to store sessions, events, and app, user, and session state in mongodb. it's experimental for now, and there's a runner example in docs/guides/integrations/mongodb/session_service to get you started. if anything's missing for your setup, please open a new issue so we can take a look.

  18. github-actions commented on Oct 26, 2026

    @github-actions

    Are you satisfied with the resolution of your issue?
    Yes
    No

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

request clarification[Status] The maintainer need clarification or more information from the authorservices[Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions