---
question: How do I page documents with AND filters?
kind: task
via_web: na
via_cli: na
via_python: available
via_api: na
via_config: na
ref_python: documents.find
prereq: The module has stored documents in a collection. See [Store a document](/user-guide/build/platform/store-a-document?via=python).
next:
  - /capabilities/build/platform/store-a-document
  - /capabilities/build/platform/documents-overview
---

# Query documents

A query filters one collection of the module's namespace with predicates, orders the matches and returns them a page at a time.

## Web UI

Not applicable. System › Data › Documents lists a collection in id order, a page at a time, and its search box only filters the rows already loaded. To filter with predicates, use the Python steps on this page.

## CLI

Not applicable. There is no `abi` command for the document service. Use the Python steps on this page.

## Python

### Find a page

```python
documents = self.engine.services.document
page = documents.find(
    "notes",
    where=[("status", "eq", "draft"), ("score", "gte", 3)],
    order_by=("score", "desc"),
    limit=20,
)
for doc in page.items:
    print(doc.id, doc.data["title"])
```

Each predicate is `(field, operator, value)`, and all of them must hold. A field is a top-level key: a dot is not a nested path. Without `order_by` the order is by id. `limit` is 1 to 1000, 100 by default.

| Operator | Value |
|---|---|
| `eq`, `ne` | Any value |
| `lt`, `lte`, `gt`, `gte` | A non-null scalar |
| `in`, `nin` | A list of at most 500 values |
| `contains` | One element of an array field (not a substring) |
| `exists` | `True` or `False` |

### Follow the cursor

```python
where = [("status", "eq", "draft"), ("score", "gte", 3)]
cursor = None
while True:
    page = documents.find("notes", where=where, order_by=("score", "desc"), limit=20, cursor=cursor)
    for doc in page.items:
        ...
    if page.cursor is None:
        break
    cursor = page.cursor
```

Only `cursor is None` means the end. A cursor belongs to its query: another filter or order raises `ValueError("Invalid cursor for this query")`. Paging is not a snapshot: a document whose sort value changes while you page can show twice or not at all.

### Or let the service page for you

```python
for doc in documents.iterate("notes", where=[("status", "eq", "draft")]):
    ...
n = documents.count("notes", where=[("status", "eq", "draft")])
first = documents.find_one("notes", [("title", "eq", "Hello")])   # Document or None
```

`iterate` reads batches of 500 by default (`batch=`). `delete_many("notes", where)` deletes every match and returns how many; it is not one transaction.

## REST API

Not applicable. The System routes of the Nexus API list a collection's documents by page (`GET /api/admin/system/resources/document/entries?parent=<namespace>/<collection>`), without predicates. The engine API has no document route. Use the Python steps on this page.

## Config

Not applicable. A query is a call, not a setting.
