Query your data
With AgentDB you find exactly the records you need. You can:
- filter records by field values and by linked records,
- sort and page through large results,
- count, sum and average without paging,
- search text across records by words,
- save a query as a view and run it again later.
Every query is exact and typed. AgentDB never guesses what you meant.
#Example data
The examples on this page use deals that belong to companies. Your agent would set this up with a few tool calls:
{"tool": "schema_define_object", "arguments": {"name": "company"}}{"tool": "schema_define_field", "arguments": {"object": "company", "name": "name", "type": "text", "unique": true}}{"tool": "schema_define_field", "arguments": {"object": "company", "name": "country", "type": "text"}}{"tool": "schema_define_object", "arguments": {"name": "deal"}}{"tool": "schema_define_field", "arguments": {"object": "deal", "name": "title", "type": "text", "unique": true}}{"tool": "schema_define_field", "arguments": {"object": "deal", "name": "stage", "type": "enum", "enum_values": ["open", "won", "lost"]}}{"tool": "schema_define_field", "arguments": {"object": "deal", "name": "amount", "type": "integer"}}{"tool": "schema_define_field", "arguments": {"object": "deal", "name": "closed_on", "type": "date"}}{"tool": "schema_define_relationship", "arguments": {"name": "for_company", "source_object": "deal", "target_object": "company", "cardinality": "one"}}{"tool": "records_upsert_batch", "arguments": {"object": "company", "match_on": "name", "records": [{"data": {"name": "Example Ltd", "country": "NL"}}, {"data": {"name": "Sample GmbH", "country": "DE"}}]}}{"tool": "records_upsert_batch", "arguments": {"object": "deal", "match_on": "title", "records": [{"data": {"title": "Website redesign", "stage": "open", "amount": 12000}}, {"data": {"title": "Support contract", "stage": "won", "amount": 4800, "closed_on": "2026-09-14"}}, {"data": {"title": "Data migration", "stage": "won", "amount": 9500, "closed_on": "2026-10-02"}}, {"data": {"title": "Training day", "stage": "lost", "amount": 1500, "closed_on": "2026-10-20"}}]}}{"tool": "relationships_link_batch", "arguments": {"source_object": "deal", "relationship": "for_company", "links": [{"source_key": {"title": "Website redesign"}, "target_key": {"name": "Example Ltd"}}, {"source_key": {"title": "Data migration"}, "target_key": {"name": "Example Ltd"}}, {"source_key": {"title": "Support contract"}, "target_key": {"name": "Sample GmbH"}}]}}#Filter records
records_query takes the object, a where filter, a sort and a limit. All conditions in where.all must match.
{"tool": "records_query", "arguments": {"object": "deal", "where": {"all": [{"field": "stage", "op": "eq", "value": "open"}, {"field": "amount", "op": "gte", "value": 10000}]}, "sort": [{"field": "amount", "order": "desc"}], "limit": 20}}The same query over REST and from the CLI:
curl -X POST https://app.agentdb.link/v1/workspaces/$AGENTDB_WORKSPACE/query \
-H "Authorization: Bearer $AGENTDB_TOKEN" \
-H "Content-Type: application/json" \
-d '{"object":"deal","where":{"all":[{"field":"stage","op":"eq","value":"open"}]}}'agentdb query --json '{"object":"deal","where":{"all":[{"field":"stage","op":"eq","value":"open"}]}}'#Operators
Which operators work depends on the field type.
| Operator | Meaning | Works on |
|---|---|---|
eq, neq | equal, not equal | most types |
in | equal to one of up to 100 values | most types |
lt, lte, gt, gte | less than, greater than | numbers, dates, times, text |
is_null, is_not_null | has no value, has a value | every type |
contains, starts_with | text contains, text starts with, ignoring case | text, email, url, phone, rich text |
contains, has_any, has_all | the list holds an item, any item, all items | multi_select, list |
within_bbox, near | inside a box, near a point | geo |
Some rules to know:
eqon text is exact and case-sensitive. Usecontainsorstarts_withto ignore case.- A field without a value never matches
eq,neqor a range. Onlyis_nullfinds it. booleanfields take onlyeq,neqand the null operators.- You can filter on the built-in fields
id,created_atandupdated_at. - A query holds at most 20 conditions.
agentdb_capabilities {"operation": "records_query"} lists the exact operators per field type.
#Filter by linked records
A relationship condition matches records whose linked records match. This finds deals for companies in NL:
{"tool": "records_query", "arguments": {"object": "deal", "where": {"all": [{"relationship": "for_company", "where": {"all": [{"field": "country", "op": "eq", "value": "NL"}]}}]}}}Add "direction": "incoming" to follow links that point at the queried object. A query holds at most 3 relationship conditions.
#Sort and page
sorttakes one field with"order": "asc"or"desc". Ties are sorted byid, so the order is stable.- Without
sort, records come oldest first. - Fields without a value come first when ascending and last when descending.
limitis 1 to 200. The default is 50.
When more records match, the result holds a next_cursor. Send it as cursor with the identical query to get the next page. A next_cursor of null means you have them all.
{"tool": "records_query", "arguments": {"object": "deal", "sort": [{"field": "amount", "order": "desc"}], "limit": 2}}{"tool": "records_query", "arguments": {"object": "deal", "sort": [{"field": "amount", "order": "desc"}], "limit": 2, "cursor": "$NEXT"}}Add "fields": ["title", "amount"] to return only those fields. Archived records stay hidden unless you add "include_archived": true.
#Count and total
Use records_aggregate for counts, sums, averages, minimums and maximums. AgentDB computes them, so you never page through records to add them up.
{"tool": "records_aggregate", "arguments": {"object": "deal", "group_by": ["stage"], "metrics": [{"op": "count"}, {"op": "sum", "field": "amount"}]}}Group date fields by hour, day, week, month or year:
{"tool": "records_aggregate", "arguments": {"object": "deal", "where": {"all": [{"field": "stage", "op": "eq", "value": "won"}]}, "group_by": [{"field": "closed_on", "bucket": "month"}], "metrics": [{"op": "sum", "field": "amount"}]}}- Group by up to 3 fields, with up to 10 metrics.
whereuses the same filter asrecords_query.countneeds no field. Every other metric needs one.
From the CLI, agentdb records count deal --by stage gives a quick count per stage.
#Full-text search
Full-text search finds records by words, ranked by relevance. Turn it on once per object. By default AgentDB indexes every text-like field.
{"tool": "search_configure", "arguments": {"object": "deal", "enabled": true}}From then on, AgentDB keeps the index current on every write. Search with records_search:
{"tool": "records_search", "arguments": {"object": "deal", "query": "website redesign"}}agentdb search query deal migration- Every word must occur. Add
"match": "any"to match at least one word. - The last word also matches as a prefix, so
migrfinds "migration". - Punctuation is ignored. A search holds at most 8 words.
- Each hit has a score, the matched fields and highlighted snippets.
- Add a
wherefilter to search only matching records.
#Saved views
A saved view is a named query that you or your agent can run again. Views are versioned. A view is private by default. With "visibility": "workspace", everyone in the workspace can use it, each with their own permissions.
{"tool": "views_create", "arguments": {"name": "open_deals", "object": "deal", "definition": {"where": {"all": [{"field": "stage", "op": "eq", "value": "open"}]}, "sort": [{"field": "amount", "order": "desc"}]}, "visibility": "workspace"}}{"tool": "views_run", "arguments": {"view": "open_deals"}}agentdb views run open_dealsA view can also describe how to show its records: as a table, list, kanban board, calendar, timeline or report. You can share a view read-only through a link. See Dashboards and sharing.
#Next steps
- Concepts explains objects, fields and relationships.
- Troubleshooting explains errors such as
INVALID_QUERY.