Skip to main content

Category Service

The category service ( internal/api/v1/instasites/services/categories.service.js ) powers /instasites/categories endpoints, delivering both categories and main categories with template counts for filter UIs.

📖 Overview

Primary responsibilities:

  • Query instasites.templates.categories and instasites.templates to build joined datasets.
  • Support free-text search, scoped category/main category filters, and count aggregation.
  • Normalize results into a flat array with id, title, type, and count fields while also returning total template counts.

🗄️ Collections Used

instasites.templates.categories

  • Operations: Read
  • Model: shared/models/instasite-template-category.js
  • Usage: Source of category and main-category metadata, as well as the driving collection for $lookup pipelines.

instasites.templates

  • Operations: Read
  • Model: shared/models/instasite-template.js
  • Usage: Supplies template documents to join against categories, enabling count aggregation per taxonomy node.

🧠 Function Reference

getCategories({ query, category_id, main_category_ids })

Purpose: Returns a combined list of categories and main categories, annotated with template counts and overall total.

Inputs:

  • query — Optional search term; performs case-insensitive $regex against category titles.
  • category_id — Focuses aggregation on a single sub-category and fetches related main categories.
  • main_category_ids — Array of main-category IDs; returns those nodes plus their linked sub-categories.

Business Logic Flow:

  1. Build a flexible aggregation (qcatego) for instasites.templates.categories:
    • No filters → return everything.
    • category_id provided → pull the category, join main categories via template relationships.
    • main_category_ids provided → pull each main category, join sub-categories via template relationships.
    • Both provided → perform a simple $match with $or.
  2. Construct parallel aggregation (customizedQuery) for instasites.templates:
    • Optionally regex match titles when query exists.
    • Use $facet to count templates grouped by category_id and main_category_id (filtered when inputs provided).
  3. Execute three asynchronous operations with Promise.all:
    • Category aggregation pipeline built in step 1.
    • Template counts facet from step 2.
    • countDocuments for total templates matching the filters.
  4. Normalize category aggregation output:
    • Flatten the data array produced by $addFields.
    • Convert _id to id for client expectations.
    • Attach count by finding the matching group in either templatesCounts.categories or templatesCounts.main_categories.
  5. Return { data, total }, where data is a merged list containing both category types.

Key Rules:

  • Every incoming ID is converted to mongoose.Types.ObjectId; invalid values throw before Mongo executes (surfaced as CastError).
  • Counts default to 0 when no templates match a node.
  • When main_category_ids and category_id are both provided, the service returns only the explicitly requested nodes and their counts.

Error Modes:

CodeScenarioResponse
400Invalid ObjectId stringsSurface as validation errors before service invocation
500Aggregation failureController catches and logs generic server error

🔍 Query Examples

ScenarioInputsOutput Notes
Search by text{ query: "health" }Returns all categories whose titles contain "health" (case-insensitive).
Main-category drilldown{ main_category_ids: ["..."] }Returns specified main categories followed by their child categories via $lookup.
Sub-category focus{ category_id: "..." }Returns the selected category along with linked main categories (through template relationships).
💬

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:31 AM