# Counting [#counting] There are two kinds of count. Count variants (`find.count`, `create.count`, `update.count`, `delete.count`) return a number instead of rows. The `$count` reducer counts the related rows of a to-many relation inside a normal read. ## Count variants [#count-variants] Every count variant takes no `select` or `include`; it returns a plain number. | Call | Takes | Returns | | -------------------------------- | ----------------------- | --------------------- | | `find.count({ where? })` | a filter | how many rows match | | `create.count({ data: [...] })` | an array of records | how many were created | | `update.count({ where?, data })` | a filter and the change | how many were updated | | `delete.count({ where? })` | a filter | how many were deleted | ```ts await avClient.User.find.count({ where: { role: "USER" } }); // 2 (of 3 users) await avClient.Category.create.count({ data: [{ name: "A1" }, { name: "A2" }] }); // 2 await avClient.Post.update.count({ where: { views: { lt: 5 } }, data: { views: { $increment: 1 } } }); // 2 (the number of rows matched and updated) await avClient.Category.delete.count({ where: { name: { startsWith: "A" } } }); // 2 ``` Use them instead of `*.many` when you only need the number: nothing is loaded and no rows travel. Over HTTP the number is the envelope's `data`: ```json {"data":3,"code":"A1000","cause":null} ``` Their codes follow the family: `find.count` answers `A1000`, `create.count` `A1003`, `update.count` `A1005`, `delete.count` `A1007`. With no match, `find.count` is `0`, and so are the bulk writes. A count variant is a separate operation: [exposure](/framework/docs/exposure#operations) can switch it off independently (`operations: { find: ["count"] }`), and `update.count` can fail like any update (a unique-constraint conflict is `A2008`). ## The `$count` reducer [#the-count-reducer] `$count` is a reducer that you list in a to-many relation's `select`; it is not a field. Its presence changes the shape of that relation's result: | Nested `select` | Result | | --------------------------- | ------------------------------------------ | | `["id", "title"]` | `{ id, title }[]` | | `["$count"]` | `{ count: number }` | | `["id", "title", "$count"]` | `{ data: { id, title }[]; count: number }` | ```ts await avClient.User.find.many({ select: ["id", { posts: { select: ["$count"] } }], orderBy: { id: "asc" }, }); // [ { id: 1, posts: { count: 2 } }, { id: 2, posts: { count: 3 } }, { id: 3, posts: { count: 1 } } ] ``` Combine rows and total in one round trip. When the relation has a `where` and pagination, `count` is the total matching rows before `limit` and `offset`, and `data` is the page. That is what a "showing 1 of N" list needs: ```ts await avClient.User.find.many({ select: ["id", { posts: { select: ["id", "$count"], where: { views: { gt: 5 } }, limit: 1, orderBy: { id: "asc" } } }], orderBy: { id: "asc" }, }); // [ { id: 1, posts: { data: [ { id: 1 } ], count: 1 } }, // { id: 2, posts: { data: [ { id: 3 } ], count: 2 } }, // 2 posts match, 1 returned // { id: 3, posts: { data: [ { id: 6 } ], count: 1 } } ] ``` With `include`, a relation can be given the reducer in the same object form; the parent still returns its default scalars: ```ts await avClient.User.find.many({ include: [{ posts: { select: ["$count"] } }], limit: 1 }); // [ { ..., id: 1, posts: { count: 2 } } ] ``` ### Order by a count [#order-by-a-count] To sort parents by how many related rows they have, use `orderBy` with `$count` ([Filtering, sorting and paging](/framework/docs/filtering-sorting-paging#ordering-by-a-relation)): ```ts await avClient.User.find.many({ orderBy: { posts: { $count: "desc" } }, select: ["id"] }); ``` ### Availability [#availability] `$count` is advertised per relation in the contract, under `capabilities.reducers`. It applies to to-many relations, and exposure can remove it (`exemptions.resources..fields.: ["reducers"]`). ## See also [#see-also] * [Relations and nested writes](/framework/docs/relations-and-nested-writes) * [Filtering, sorting and paging](/framework/docs/filtering-sorting-paging) * [Querying](/framework/docs/querying): the argument reference.