How to Filter Memories by user_id, agent_id, or run_id in Mem0

To filter memories in Mem0, pass a dictionary containing user_id, agent_id, and/or run_id to the filters parameter of the search() or list() methods, which the underlying vector store converts to native query syntax.

Mem0 (from the mem0ai/mem0 repository) stores every memory vector alongside a payload containing arbitrary metadata. The framework provides a unified filtering interface that works across Qdrant, Valkey, Pinecone, and other vector stores, allowing you to scope queries to specific users, agents, or execution runs.

How Filtering Works at the Vector Store Layer

Mem0 implements filtering at two architectural layers. The vector store layer translates Python dictionaries into database-specific query languages, while the SDK layer exposes a consistent API regardless of your backend.

In mem0/vector_stores/base.py, the abstract list(self, filters=None, limit=None) method defines the contract that every storage backend must implement. Concrete implementations in qdrant.py and valkey.py handle the translation:

  • Qdrant (mem0/vector_stores/qdrant.py, lines 41-61): Converts the filters dict into a Qdrant Filter object composed of FieldCondition instances.
  • Valkey (mem0/vector_stores/valkey.py, lines 558-567): Constructs a RediSearch query string using the syntax @user_id:{alice} @agent_id:{agent1} @run_id:{run1}.

Filtering Memories with the Python SDK

The high-level Mem0 client exposes search() for similarity-based retrieval and list() for direct metadata queries. Both methods accept a filters dictionary supporting any combination of the three identifier keys.

Search with Similarity and Filters

Use search() when you need semantic similarity combined with metadata constraints. The method embeds your query, retrieves nearest neighbors, and applies the payload filters before returning results.

from mem0 import Mem0

mem = Mem0(
    embedding_model="all-MiniLM-L6-v2",
    vector_store="qdrant",
    collection_name="my_memories",
)

results = mem.search(
    query="What did I ask about the budget?",
    limit=5,
    filters={
        "user_id": "alice",
        "agent_id": "agent1",
        "run_id": "run1",
    },
)

for r in results:
    print(r.payload)

Omitted keys in the filters dict are ignored, allowing flexible query scoping.

List Memories by Metadata Only

Use list() when you need to retrieve all memories matching specific metadata without vector similarity search. This executes a pure metadata filter against the vector store.

matches = mem.list(
    filters={
        "user_id": "alice",
        "agent_id": "agent1",
        "run_id": "run1",
    },
    limit=100,
)

for m in matches:
    print(m.id, m.payload)

Implementation Details by Vector Store

Different storage backends translate the filters dictionary into their native query languages.

Qdrant Implementation

In mem0/vector_stores/qdrant.py, the _create_filter method constructs a Qdrant Filter object. Each key-value pair in your filters dict becomes a FieldCondition that Qdrant applies during the vector search.


# Conceptual implementation from qdrant.py

from qdrant_client.models import Filter, FieldCondition, MatchValue

def _create_filter(self, filters):
    conditions = [
        FieldCondition(key=k, match=MatchValue(value=v))
        for k, v in filters.items()
    ]
    return Filter(must=conditions)

Valkey Implementation

In mem0/vector_stores/valkey.py, the implementation builds a RediSearch query string. The filters dict is converted to the RediSearch tag syntax:


# From valkey.py lines 558-567

query_parts = [f"@{k}:{{{v}}}" for k, v in filters.items()]
rediserch_query = " ".join(query_parts)

# Result: @user_id:{alice} @agent_id:{agent1} @run_id:{run1}

Using the REST API

The OpenMemory HTTP API exposes a /api/v1/memories/filter endpoint defined in openmemory/api/app/routers/memories.py (lines 45-66). Currently, this endpoint filters by user, application, category, and date ranges, but does not expose the generic filters dictionary for agent_id or run_id.

To enable full filtering via HTTP, extend the request model to accept a filters field and forward it to the SDK:

from typing import Dict, Optional
from pydantic import BaseModel

class FilterMemoriesRequest(BaseModel):
    user_id: str
    page: int = 1
    size: int = 10
    filters: Optional[Dict[str, str]] = None  # Add this field

# In the endpoint handler:

results = mem_client.list(
    filters=request.filters,
    limit=request.size,
)

Summary

  • Mem0 stores user_id, agent_id, and run_id in each memory's payload metadata.
  • Pass a filters dictionary to mem.search() or mem.list() to scope results by these fields.
  • Qdrant converts filters to Filter objects with FieldCondition instances.
  • Valkey converts filters to RediSearch query strings using tag syntax (@field:{value}).
  • The REST API can be extended to support these filters by adding a filters field to the request model in memories.py.

Frequently Asked Questions

Can I filter by only one of the IDs, or do I need all three?

You can filter by any combination. The filters dictionary accepts any subset of user_id, agent_id, and run_id. Omitting a key means that dimension is not constrained in the query, allowing you to filter by just user_id, by user_id and agent_id together, or any other combination.

Does filtering work with all vector store backends?

Yes. The base class in mem0/vector_stores/base.py mandates that all implementations support the filters parameter in their list() method. Whether using Qdrant, Valkey (Redis), Pinecone, or another supported store, the SDK translates the Python dictionary into the native query syntax automatically.

How do I filter memories for a specific user across all agents?

Pass only the user_id key in your filters dictionary:

results = mem.list(filters={"user_id": "alice"}, limit=50)

This returns all memories where the payload contains "user_id": "alice" regardless of which agent_id or run_id created them.

Is there a performance difference between search() and list() when filtering?

Yes. search() performs a vector similarity search first, then applies filters, which is computationally heavier. list() applies metadata filters directly against the vector store indexes without computing vector distances, making it faster for pure metadata retrieval. Use list() when you only need to filter by IDs and do not require semantic similarity matching.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →