--- title: Category tags: [data-model, mongoose] aliases: [Category Model, Taxonomy, ICategory] --- # Category Hierarchical taxonomy node used by [[PurchaseRequest]] and [[RequestTemplate]]. Each row is bilingual (`name` in the local language, `nameEn` in English), supports parent/child via `parentId`, has an icon and a display `order`, and an `isActive` toggle for soft-removal. > [!note] Source > `backend/src/models/Category.ts:15` — schema definition > `backend/src/models/Category.ts:60` — model export ## Schema | Field | Type | Required | Default | Validation | Index | Description | | --- | --- | --- | --- | --- | --- | --- | | `name` | String | yes | — | trim | yes | Local language name. | | `nameEn` | String | yes | — | trim | yes | English name. | | `description` | String | no | — | trim | — | Description. | | `icon` | String | no | — | trim | — | Icon identifier / URL. | | `isActive` | Boolean | no | `true` | — | yes | Active flag. | | `parentId` | ObjectId → [[Category]] | no | `null` | — | yes | Parent category (`null` for top level). | | `order` | Number | no | `0` | — | — | Display order. | | `createdAt` | Date | auto | — | — | — | Mongoose timestamp. | | `updatedAt` | Date | auto | — | — | — | Mongoose timestamp. | ## Virtuals None defined. ## Indexes Defined at `backend/src/models/Category.ts:55-58`: - `{ name: 1 }` - `{ nameEn: 1 }` - `{ isActive: 1 }` - `{ parentId: 1 }` ## Pre/Post Hooks None declared. ## Instance Methods None defined. ## Static Methods None defined. ## Relationships - **References**: [[Category]] (self, via `parentId`). - **Referenced by**: [[PurchaseRequest]] (`categoryId`), [[RequestTemplate]] (`categoryId`). ## State Transitions No status field — only the `isActive` boolean for soft-disable. ```mermaid stateDiagram-v2 [*] --> active active --> inactive : admin disables inactive --> active : admin re-enables ``` ## Common Queries ```ts // Top-level categories Category.find({ parentId: null, isActive: true }).sort({ order: 1 }); // Children of a category Category.find({ parentId, isActive: true }).sort({ order: 1 }); // Bilingual search Category.find({ $or: [{ name: regex }, { nameEn: regex }], isActive: true }); // Full tree (basic, two-level) const roots = await Category.find({ parentId: null }).sort({ order: 1 }); const children = await Category.find({ parentId: { $in: roots.map(r => r._id) } }); ``` Related: [[PurchaseRequest]], [[RequestTemplate]].