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

> Learn how to filter memories in Mem0 using user_id, agent_id, or run_id. Easily refine your memory searches in your AI applications with simple parameter settings.

- Repository: [Mem0/mem0](https://github.com/mem0ai/mem0)
- Tags: how-to-guide
- Published: 2026-03-07

---

**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`](https://github.com/mem0ai/mem0/blob/main/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`](https://github.com/mem0ai/mem0/blob/main/qdrant.py) and [`valkey.py`](https://github.com/mem0ai/mem0/blob/main/valkey.py) handle the translation:

- **Qdrant** ([`mem0/vector_stores/qdrant.py`](https://github.com/mem0ai/mem0/blob/main/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`](https://github.com/mem0ai/mem0/blob/main/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.

```python
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.

```python
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`](https://github.com/mem0ai/mem0/blob/main/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.

```python

# 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`](https://github.com/mem0ai/mem0/blob/main/mem0/vector_stores/valkey.py), the implementation builds a RediSearch query string. The `filters` dict is converted to the RediSearch tag syntax:

```python

# 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`](https://github.com/mem0ai/mem0/blob/main/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:

```python
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`](https://github.com/mem0ai/mem0/blob/main/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`](https://github.com/mem0ai/mem0/blob/main/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:

```python
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.