Database service

Introduction#

DatabaseService is the MongoDB facade. Notices, jobs, offers, users, policies. Upserts, merge logic for offers, ObjectId serialization for JSON, and the DI boundary that keeps business code off raw pymongo.

It owns:

  • Centralized MongoDB access via DBClient
  • Notice lifecycle management (existence checks, insertion, retrieval, marking as sent)
  • Structured job upsert operations
  • Complex merge logic for placement offers with role merging and package comparisons
  • User management (add/reactivate/deactivate)
  • Policy operations (upsert by year)
  • Serialization of ObjectId fields for JSON transport
  • Error handling and logging

Project structure#

The DatabaseService resides in the services layer and collaborates with the DBClient for raw MongoDB connectivity. It integrates with other system components through dependency injection, so CLI commands and long-running servers can share the same wiring.

Core components#

  • DatabaseService: Implements MongoDB operations for notices, jobs, placement offers, users, and policies. Provides CRUD methods, merge logic for placement offers, and serialization helpers.
  • DBClient: Handles MongoDB connection establishment, collection initialization, and connection lifecycle.
  • Configuration: Centralized settings management including MongoDB connection string and logging configuration.

It can:

  • Notice management: existence checks, insertions, retrieval, unsent notice enumeration, and marking as sent.
  • Structured job upsert: merges incoming job data with existing records.
  • Placement offers: bulk save with merge logic for roles and student packages, emitting events for downstream processing.
  • User management: add/reactivate/deactivate users with soft delete semantics.
  • Policy operations: upsert by year with change detection.
  • Serialization: converts ObjectId fields to strings for JSON transport.

Architecture overview#

The DatabaseService follows a layered architecture:

  • Clients layer: DBClient manages raw MongoDB connectivity and exposes typed collection properties.
  • Services layer: DatabaseService wraps DBClient and adds business logic for CRUD operations, merge algorithms, and serialization.
  • Orchestration layer: CLI commands and runners instantiate DBClient and DatabaseService, passing them to dependent services.

Detailed component analysis#

DatabaseService class#

The DatabaseService class encapsulates all MongoDB operations and acts as the primary data access object for notices, jobs, placement offers, users, and policies.

Notice operations#

The notice subsystem provides lifecycle management for notifications:

  • Existence checks by unique notice id
  • Bulk retrieval of notice ids for efficient lookups
  • Insertion with automatic timestamps and sent flags
  • Retrieval by id and chronological enumeration of unsent notices
  • Marking as sent with timestamps

Structured job operations#

Structured job upsert maintains normalized job listings:

  • Existence checks by structured id
  • Upsert logic that merges incoming data with existing records
  • Timestamp management for created/updated records

Placement offer processing with merge logic#

The placement offers subsystem implements a complex merge algorithm built to:

  • Group offers by company name
  • Merge roles with package comparison (higher package wins)
  • Merge students with package comparison and role updates
  • Track newly added students for event emission
  • Emit events for new offers and updated offers

User management#

User management provides soft-deletion semantics:

  • Add or reactivate users with activation flag
  • Deactivate users (soft delete)
  • Retrieve active users and user statistics

Policy operations#

Policy operations manage official policy documents by year:

  • Upsert by year with upsert semantics
  • Change detection and logging
  • Retrieval of published policies

Serialization mechanisms for MongoDB ObjectId#

The DatabaseService includes a serialization helper to convert ObjectId fields to strings for JSON transport:

  • Converts top-level _id field to string
  • Can be extended for nested ObjectId fields if needed

Integration patterns with other system components#

DatabaseService integrates with other components through dependency injection:

  • CLI commands: main.py orchestrates DBClient and DatabaseService creation for email processing and official data updates
  • NotificationRunner: creates its own DBClient/DatabaseService instance for sending unsent notices
  • NotificationService: relies on DatabaseService for fetching unsent notices and marking them as sent
  • OfficialPlacementService: uses DatabaseService to persist scraped official placement data

Dependency analysis#

The DatabaseService exhibits low coupling and high cohesion:

  • Coupling: Minimal direct coupling to DBClient; all MongoDB operations delegated to DBClient collections
  • Cohesion: High cohesion around data access patterns and business logic for each entity type
  • External dependencies: PyMongo for MongoDB connectivity, datetime for timestamps, typing for type hints

Performance considerations#

  • Connection pooling: DBClient uses PyMongo’s built-in connection pooling; ensure appropriate pool sizing for production workloads
  • Index usage: The database schema defines indexes for frequent query patterns (e.g., notices by sent flags, jobs by deadlines)
  • Query optimization: Prefer targeted queries with projections and limits; avoid loading entire collections
  • Batch operations: Use bulk operations for large-scale updates (e.g., marking notices as sent)
  • Serialization overhead: ObjectId conversion is lightweight; avoid unnecessary conversions in hot paths
  • Logging impact: safe_print is used for operational logging; consider structured logging for production monitoring

[No sources needed since this section provides general guidance]

Troubleshooting guide#

Common issues and resolutions:

  • Connection failures: Verify MONGO_CONNECTION_STR environment variable and network connectivity
  • Missing collections: Ensure database initialization occurs before accessing collections
  • Duplicate key errors: Use upsert operations for notices/jobs/policies; placement offers merge prevents duplicates
  • Serialization errors: Use _serialize_doc for ObjectId fields when returning JSON responses
  • Performance bottlenecks: Review query plans and add missing indexes as per DATABASE.md

Conclusion#

DatabaseService is the MongoDB facade everyone else calls. CRUD, offer merges, ObjectId serialization. Indexes, sane config, and logs matter more here than clever code.