Skip to main content
Repositories in Orionjs handle data access operations, separating data access logic from business logic. They should focus exclusively on database interactions.

Structure and Naming

  • Use @Repository() decorator from @orion-js/mongodb
  • Each repository should manage a single entity type
  • Follow naming convention: {EntityNameInPlural}Repo (e.g., UsersRepo, CardsRepo)
  • Put repositories in app/{component}/repos/{EntityNameInPlural}Repo/index.ts
  • Collection name should be {component_name}.{plural_of_entity} (e.g., gaming.pokemon_cards)

Best Practices

  • Keep methods simple and focused on a single responsibility
  • Never access the collection directly outside the repository. All database interactions must go through repository methods. The only exception is during migrations.
  • Return plain objects or domain models, not database-specific structures
  • Use descriptive method names: findById, findByEmail, create{EntityName}, update{EntityName}, delete{EntityName}
  • Avoid business logic in repositories (use services instead)
  • Add proper typing for all parameters and return values
  • Always use typedId() in schema definitions for document IDs
  • Use InferSchemaType to derive types from schemas

Naming Convention: get vs load

Use the load prefix instead of get for methods where data freshness is not guaranteed: Use load prefix when the method:
  • Uses secondaryPreferred read preference (eventually consistent reads from replica secondaries)
  • Uses DataLoader methods like loadById, loadMany (batched/deduplicated reads within request scope)
  • Reads from cache (in-memory, Redis, or any caching layer)
Use get prefix when the method:
  • Reads directly from primary with no caching
  • Requires guaranteed data freshness (read-after-write scenarios)
Examples:
  • getCardsListCursorloadCardsListCursor (uses secondaryPreferred)
  • getCardByIdloadCardById (if using DataLoader or cache)
  • findById stays as is (direct primary read)

Read Preferences for Non-Critical Queries

For queries that don’t require strong consistency, use the readPreference: 'secondaryPreferred' option to distribute read load across MongoDB replica set secondaries. This is especially important for:
  • Aggregations: Heavy aggregation pipelines
  • List queries: Paginated lists or search results
  • Reports and analytics: Read-heavy operations for dashboards
  • Count operations: Document counts for UI display
When NOT to use secondaryPreferred:
  • When reading data immediately after a write (use primary for read-after-write consistency)
  • For critical operations where stale data could cause issues
  • When the query result will be used to make a write decision

Complete Example

Integration with Services

Services should inject repositories for data access:

Why Use Repositories?

While repositories are functionally similar to services (both use dependency injection), they serve different purposes:
  • Services handle business logic, orchestration, and use cases
  • Repositories focus exclusively on data access and persistence
This separation of concerns leads to:
  • Cleaner code organization
  • Easier testing
  • Better maintainability
  • Clearer dependencies