> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anysite.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Data Analysis (query_cache)

> Server-side data filtering, aggregation, and export without consuming context window tokens

## Server-Side Data Analysis

<Note>
  `query_cache` is one of the most powerful features of the MCP Server — it allows you to **analyze data without consuming context window tokens**.
</Note>

### The Problem

When you search for 50 LinkedIn profiles, all 50 results are returned into the LLM's context. Filtering, sorting, or aggregating requires the LLM to process all data in-context — expensive and limited by context size.

### The Solution: ClickHouse-Backed Cache

Every `execute()` call stores results in a ClickHouse cache (TTL: 7 days). The `query_cache` tool lets you query this cache server-side — only the filtered/aggregated results are returned to context.

```text theme={null}
execute("linkedin", "search", "search_users", {keywords: "CTO", count: 100})
  → Returns first 10 items + cache_key
  → All 100 results stored in ClickHouse cache

query_cache(cache_key, conditions=[{field: "followers", op: ">", value: 5000}])
  → Returns only matching profiles (server-side filtering)
  → Context receives only the filtered subset, not all 100
```

***

## Filtering

Use `conditions` to filter cached results by any field:

```json theme={null}
query_cache(cache_key, conditions=[
  {"field": "location", "op": "contains", "value": "San Francisco"},
  {"field": "followers", "op": ">", "value": 500}
])
```

Multiple conditions are combined with AND logic.

### Supported Filter Operators

| Operator       | Description         | Example                                                      |
| -------------- | ------------------- | ------------------------------------------------------------ |
| `=`            | Exact match         | `{"field": "country", "op": "=", "value": "US"}`             |
| `!=`           | Not equal           | `{"field": "status", "op": "!=", "value": "inactive"}`       |
| `>`            | Greater than        | `{"field": "followers", "op": ">", "value": 1000}`           |
| `<`            | Less than           | `{"field": "age", "op": "<", "value": 30}`                   |
| `>=`           | Greater or equal    | `{"field": "score", "op": ">=", "value": 4.5}`               |
| `<=`           | Less or equal       | `{"field": "price", "op": "<=", "value": 100}`               |
| `contains`     | Substring match     | `{"field": "title", "op": "contains", "value": "Engineer"}`  |
| `not_contains` | Substring exclusion | `{"field": "bio", "op": "not_contains", "value": "retired"}` |

***

## Aggregation

Calculate summary statistics without loading individual records:

```json theme={null}
query_cache(cache_key, aggregate={"field": "followers", "op": "avg"})
```

### Supported Aggregation Functions

| Function | Description         | Example                               |
| -------- | ------------------- | ------------------------------------- |
| `count`  | Count records       | `{"op": "count"}` (field optional)    |
| `sum`    | Sum values          | `{"field": "likes", "op": "sum"}`     |
| `avg`    | Average value       | `{"field": "followers", "op": "avg"}` |
| `min`    | Minimum value       | `{"field": "price", "op": "min"}`     |
| `max`    | Maximum value       | `{"field": "score", "op": "max"}`     |
| `uniq`   | Count unique values | `{"field": "country", "op": "uniq"}`  |

***

## Group By

Combine aggregation with grouping to get breakdowns:

```json theme={null}
query_cache(cache_key, aggregate={"field": "followers", "op": "count"}, group_by="industry")
```

**Result:**

```json theme={null}
{
  "aggregate": {
    "groups": {
      "Technology": 45,
      "Finance": 23,
      "Healthcare": 12
    },
    "op": "count"
  },
  "cache_key": "abc123..."
}
```

***

## Sorting

Sort cached results by any field:

```json theme={null}
query_cache(cache_key, sort_by="followers", sort_order="desc", limit=10)
```

Returns only the top 10 results — the rest stay in cache, not in context.

***

## Combined Example

A full workflow combining all features:

```text theme={null}
1. execute("linkedin", "search", "search_users", {keywords: "VP Engineering", count: 200})
   → 200 profiles cached, first 10 returned + cache_key

2. query_cache(cache_key, conditions=[
     {field: "location", op: "contains", value: "Bay Area"},
     {field: "followers", op: ">", value: 500}
   ])
   → Filter to Bay Area VPs with 500+ followers

3. query_cache(cache_key,
     aggregate={field: "followers", op: "avg"},
     group_by="company")
   → Average follower count by company (across all 200 profiles, not just the Bay Area subset)

4. query_cache(cache_key,
     sort_by="followers", sort_order="desc", limit=5)
   → Top 5 most-followed VPs (from all 200 profiles)

5. export_data(cache_key, "csv")
   → Download all 200 profiles as CSV file
```

<Tip>
  **Key benefit**: Step 1 makes a single API call to collect data. Steps 2-5 are cache operations at zero additional API cost — they don't load all 200 profiles into context. Only the filtered/aggregated results are returned to the LLM.
</Tip>

***

## Export Data

Download full cached datasets as files:

```json theme={null}
export_data(cache_key, "csv")
```

<Warning>
  `export_data` always exports the **full dataset** stored under the `cache_key`, regardless of any filters applied via `query_cache`. Filters only affect what is returned to context — they do not modify the cached data.
</Warning>

### Supported Formats

| Format  | Description                      |
| ------- | -------------------------------- |
| `json`  | JSON array                       |
| `csv`   | Comma-separated values           |
| `jsonl` | JSON Lines (one record per line) |

Returns a download URL. Data stays cached for 7 days.

***

## Best Practices

<CardGroup cols={2}>
  <Card title="Use Large Counts" icon="arrow-up">
    Fetch more data with `execute()` (count: 100-200), then filter with `query_cache`. Cheaper than multiple small requests.
  </Card>

  <Card title="Filter Before Reading" icon="filter">
    Always use `query_cache` to narrow results before loading them into context. Saves tokens and improves response quality.
  </Card>

  <Card title="Aggregate Server-Side" icon="calculator">
    Use aggregation functions instead of asking the LLM to calculate averages, counts, or sums from raw data.
  </Card>

  <Card title="Export for External Use" icon="download">
    Use `export_data` when you need the full dataset outside of the AI conversation (spreadsheets, databases, reports).
  </Card>
</CardGroup>
