---
slug: examples/retrieve-delete-count
title: Retrieve, delete and count
kind: howto
surface: vectors
summary: Complete Python and JavaScript examples for fetching Aetherfy points by id, deleting by id list or by filter, and counting points, including the divergent exact default between the two SDKs.
sources:
  - aetherfy-vectors-python-sdk:aetherfy_vectors/client.py
  - aetherfy-vectors-python-sdk:aetherfy_vectors/models.py
  - aetherfy-vectors-js-sdk:src/client.ts
  - aetherfy-vectors-js-sdk:src/models.ts
---

# Retrieve, delete and count

Three point-level operations that do not involve a vector search: fetch known points by id, remove points, and count them.

```bash
export AETHERFY_API_KEY="afy_live_your_key_here"
```

## Setting up an Aetherfy collection for these examples

### Python setup

Install with `pip install aetherfy-vectors`.

```python
from aetherfy_vectors import AetherfyVectorsClient
from aetherfy_vectors.models import VectorConfig, DistanceMetric, Point

client = AetherfyVectorsClient()

client.create_collection(
    "inventory",
    VectorConfig(size=4, distance=DistanceMetric.COSINE),
)

client.upsert("inventory", [
    Point(id=1, vector=[0.10, 0.20, 0.30, 0.40],
          payload={"sku": "MOU-1", "category": "electronics", "price": 24.99}),
    Point(id=2, vector=[0.15, 0.18, 0.33, 0.41],
          payload={"sku": "KEY-2", "category": "electronics", "price": 189.00}),
    Point(id=3, vector=[0.12, 0.22, 0.29, 0.38],
          payload={"sku": "HUB-3", "category": "electronics", "price": 39.50}),
    Point(id=4, vector=[0.90, 0.10, 0.05, 0.02],
          payload={"sku": "MUG-4", "category": "kitchen", "price": 12.50}),
])
```

### JavaScript setup

Install with `npm install aetherfy-vectors` (Node >= 20).

```typescript
import { AetherfyVectorsClient, DistanceMetric } from 'aetherfy-vectors';

const client = new AetherfyVectorsClient();

await client.createCollection('inventory', { size: 4, distance: DistanceMetric.COSINE });

await client.upsert('inventory', [
  { id: 1, vector: [0.10, 0.20, 0.30, 0.40],
    payload: { sku: 'MOU-1', category: 'electronics', price: 24.99 } },
  { id: 2, vector: [0.15, 0.18, 0.33, 0.41],
    payload: { sku: 'KEY-2', category: 'electronics', price: 189.00 } },
  { id: 3, vector: [0.12, 0.22, 0.29, 0.38],
    payload: { sku: 'HUB-3', category: 'electronics', price: 39.50 } },
  { id: 4, vector: [0.90, 0.10, 0.05, 0.02],
    payload: { sku: 'MUG-4', category: 'kitchen', price: 12.50 } },
]);
```

## Retrieving Aetherfy points by id in Python

`retrieve` fetches known points directly. It is not a search: there is no query vector, no score, and no ranking. Order is not guaranteed to match the order of the ids you passed, and ids that do not exist are simply absent from the result rather than returned as null.

```python
from aetherfy_vectors import AetherfyVectorsClient

client = AetherfyVectorsClient()

points = client.retrieve("inventory", [1, 3], with_payload=True)
for p in points:
    print(p)
# {'id': 1, 'payload': {'sku': 'MOU-1', 'category': 'electronics', 'price': 24.99}}
# {'id': 3, 'payload': {'sku': 'HUB-3', 'category': 'electronics', 'price': 39.5}}

# Ask for the stored vectors as well.
points = client.retrieve("inventory", [1], with_payload=True, with_vectors=True)
print(points[0]["vector"])
# [0.1, 0.2, 0.3, 0.4]

# Missing ids are omitted, not reported.
print(len(client.retrieve("inventory", [1, 999])))  # 1

client.close()
```

`retrieve` returns a `List[Dict]` in the Aetherfy Python SDK — plain dictionaries, not `Point` dataclasses, so index them with `p["id"]` rather than `p.id`.

## Retrieving Aetherfy points by id in JavaScript

```typescript
import { AetherfyVectorsClient } from 'aetherfy-vectors';

const client = new AetherfyVectorsClient();

async function main() {
  const points = await client.retrieve('inventory', [1, 3], { withPayload: true });
  for (const p of points) console.log(p);
  // { id: 1, payload: { sku: 'MOU-1', category: 'electronics', price: 24.99 } }
  // { id: 3, payload: { sku: 'HUB-3', category: 'electronics', price: 39.5 } }

  const withVecs = await client.retrieve('inventory', [1], {
    withPayload: true,
    withVectors: true,
  });
  console.log(withVecs[0].vector);
  // [ 0.1, 0.2, 0.3, 0.4 ]

  console.log((await client.retrieve('inventory', [1, 999])).length); // 1

  client.dispose();
}

main();
```

The JS SDK types the result as `Point[]`, so `p.id`, `p.payload` and `p.vector` are property accesses.

## Retrieve options in Aetherfy

| Python keyword | JavaScript option | Default | Effect |
| --- | --- | --- | --- |
| `with_payload` | `withPayload` | `True` / `true` | Include the stored payload |
| `with_vectors` | `withVectors` | `False` / `false` | Include the stored vector |

Ids obey the usual Aetherfy rules: an unsigned integer up to `2**53 - 1`, or a UUID string. A slug such as `"MOU-1"` is rejected client-side with `ValidationError`, which is why the SKU above lives in the payload and not in the id.

## Deleting Aetherfy points by id in Python

`delete` takes a *points selector*. Passing a list means "these ids".

```python
from aetherfy_vectors import AetherfyVectorsClient

client = AetherfyVectorsClient()

ok = client.delete("inventory", [4])
print(ok)                                  # True
print(client.count("inventory"))           # 3
print(len(client.retrieve("inventory", [4])))  # 0

client.close()
```

## Deleting Aetherfy points by filter in Python

Passing a filter object to the same parameter means "every point matching this". The filter uses the standard `must` / `should` / `must_not` vocabulary.

```python
from aetherfy_vectors import AetherfyVectorsClient

client = AetherfyVectorsClient()

ok = client.delete("inventory", {
    "must": [
        {"key": "category", "match": {"value": "electronics"}},
        {"key": "price", "range": {"gte": 100}},
    ]
})
print(ok)                         # True
print(client.count("inventory"))  # 2

client.close()
```

There is no dry-run mode. Count first with the identical filter if you want to know what a delete will remove:

```python
doomed = client.count("inventory", count_filter={
    "must": [{"key": "category", "match": {"value": "electronics"}}]
})
print(doomed)  # 2
```

## Deleting Aetherfy points in JavaScript

The same single parameter accepts either form.

```typescript
import { AetherfyVectorsClient } from 'aetherfy-vectors';

const client = new AetherfyVectorsClient();

async function main() {
  // By id list.
  console.log(await client.delete('inventory', [4])); // true

  // By filter. In JavaScript the clause key is mustNot; the SDK sends must_not.
  console.log(await client.delete('inventory', {
    must: [
      { key: 'category', match: { value: 'electronics' } },
      { key: 'price', range: { gte: 100 } },
    ],
    mustNot: [{ key: 'sku', match: { value: 'MOU-1' } }],
  })); // true

  console.log(await client.count('inventory', { exact: true })); // 2

  client.dispose();
}

main();
```

In JavaScript write `mustNot`; the SDK translates it to the wire key `must_not`. Writing `must_not` directly in JavaScript throws, because the SDK validates clause keys against `must`, `mustNot` and `should`. That strictness matters most on `delete`: an exclusion clause that failed silently here would destroy data rather than merely return an extra row. Full detail in [Filtered search](/examples/filtered-search).

## Deleting Aetherfy points: the selector contract

| Selector value | Meaning |
| --- | --- |
| A list/array of ids | Delete exactly those points |
| A filter object (`must` / `should` / `must_not`) | Delete every point matching the filter |

`delete` returns a `bool` in Python and resolves to a `boolean` in JavaScript. Neither SDK returns the number of points removed — call `count` before and after if you need that figure.

## Counting Aetherfy points, and the exact default that differs

`count` returns a plain integer. It accepts an optional filter and an `exact` flag.

**The two SDKs ship different defaults for `exact`.** This is the single most likely source of a "the numbers don't match between our Python job and our Node service" bug.

| SDK | Signature | Default for `exact` |
| --- | --- | --- |
| Python | `count(collection_name, count_filter=None, exact=True)` | `True` — exact count |
| JavaScript | `count(collectionName, { countFilter?, exact? })` | `false` — approximate count |

An exact count scans to produce a precise number and costs more on a large collection. An approximate count is cheaper and may be off. Neither default is wrong, but they are not the same, so **pass `exact` explicitly in both languages** whenever the number is compared, asserted on, or shown to a user.

### Counting in Aetherfy with Python

```python
from aetherfy_vectors import AetherfyVectorsClient

client = AetherfyVectorsClient()

# Default is exact=True in Python.
print(client.count("inventory"))                  # 4

# Be explicit anyway.
print(client.count("inventory", exact=True))      # 4

# Cheaper approximate count.
print(client.count("inventory", exact=False))     # approximate integer

# Counting a subset.
print(client.count(
    "inventory",
    count_filter={"must": [{"key": "category", "match": {"value": "electronics"}}]},
    exact=True,
))                                                # 3

client.close()
```

### Counting in Aetherfy with JavaScript

```typescript
import { AetherfyVectorsClient } from 'aetherfy-vectors';

const client = new AetherfyVectorsClient();

async function main() {
  // Default is exact: false in JavaScript — this may be approximate.
  console.log(await client.count('inventory'));

  // Match the Python default explicitly.
  console.log(await client.count('inventory', { exact: true })); // 4

  // Counting a subset.
  console.log(await client.count('inventory', {
    countFilter: { must: [{ key: 'category', match: { value: 'electronics' } }] },
    exact: true,
  })); // 3

  client.dispose();
}

main();
```

## Aetherfy method reference for this page

| Operation | Python | JavaScript | Returns |
| --- | --- | --- | --- |
| Fetch by id | `retrieve(collection_name, ids, with_payload=True, with_vectors=False)` | `retrieve(collectionName, ids, { withPayload?, withVectors? })` | `List[Dict]` / `Promise<Point[]>` |
| Delete | `delete(collection_name, points_selector)` | `delete(collectionName, pointsSelector)` | `bool` / `Promise<boolean>` |
| Count | `count(collection_name, count_filter=None, exact=True)` | `count(collectionName, { countFilter?, exact? })` | `int` / `Promise<number>` |

Related: [Filtered search](/examples/filtered-search) for the filter object, [Collection lifecycle & schema](/examples/collection-lifecycle) for removing a whole collection instead of its points.
