Mongoose

MongoDB integration via Mongoose with injectable models and type-safe DI.

@miiajs/mongoose integrates Mongoose with MiiaJS, providing connection management, model compilation, and direct model injection via DI.

Installation

npm install @miiajs/mongoose mongoose

Setup

Configure the module

import { Module } from '@miiajs/core'
import { MongooseModule } from '@miiajs/mongoose'

@Module({
  imports: [
    MongooseModule.configure({
      uri: 'mongodb://localhost:27017/myapp',
    }),
  ],
})
class AppModule {}

With ConfigService (from @miiajs/config):

import { ConfigService } from '@miiajs/config'

MongooseModule.configure((resolve) => {
  const config = resolve(ConfigService)
  return {
    uri: config.getOrThrow('MONGODB_URL'),
    retry: { attempts: 10, delay: 10_000 },
  }
})

Configuration options

interface MongooseModuleOptions {
  uri: string                              // MongoDB connection URI
  connectionOptions?: mongoose.ConnectOptions // Mongoose connect options
  retry?: {
    attempts?: number                      // Default: 10
    delay?: number                         // Default: 10_000 ms
  }
}

Define models

Use defineModel to pair a name with a native Mongoose schema. The result is a ModelRef used for registration and type-safe injection.

import { Schema } from 'mongoose'
import { defineModel } from '@miiajs/mongoose'

export interface IUser {
  name: string
  email: string
  role: string
}

export const User = defineModel<IUser>('User', new Schema<IUser>({
  name: { type: String, required: true },
  email: { type: String, required: true },
  role: { type: String, default: 'user' },
}, { timestamps: true }))

For schemas with plugins or middleware, define the schema separately:

const userSchema = new Schema<IUser>({
  name: { type: String, required: true },
  email: { type: String, required: true },
})

userSchema.plugin(autopopulate)
userSchema.pre('save', async function () {
  // pre-save logic
})

export const User = defineModel('User', userSchema)

Register models

Register models per feature module:

import { Module } from '@miiajs/core'
import { MongooseModule } from '@miiajs/mongoose'
import { User } from './user.model.js'

@Module({
  imports: [MongooseModule.register([User])],
  controllers: [UserController],
  providers: [UserService],
})
class UserModule {}

Models from multiple register() calls accumulate and are available when the app starts.

Use in services

Inject models directly using injectModel or @InjectModel:

import { Injectable } from '@miiajs/core'
import { injectModel } from '@miiajs/mongoose'
import { User } from './user.model.js'

@Injectable()
class UserService {
  private users = injectModel(User)

  async findAll() {
    return this.users.find()
  }

  async findById(id: string) {
    return this.users.findById(id)
  }

  async create(data: { name: string; email: string }) {
    return this.users.create(data)
  }

  async update(id: string, data: Record<string, any>) {
    return this.users.findByIdAndUpdate(id, data, { new: true })
  }

  async delete(id: string) {
    const result = await this.users.deleteOne({ _id: id })
    return result.deletedCount > 0
  }
}

Decorator style:

import { Injectable } from '@miiajs/core'
import { InjectModel } from '@miiajs/mongoose'
import type { Model } from 'mongoose'
import { User, type IUser } from './user.model.js'

@Injectable()
class UserService {
  @InjectModel(User) private users!: Model<IUser>
}

Raw connection access

For advanced operations, inject MongooseService directly:

import { inject, Injectable } from '@miiajs/core'
import { MongooseService } from '@miiajs/mongoose'

@Injectable()
class MigrationService {
  private mongoose = inject(MongooseService)

  async runAggregation() {
    return this.mongoose.connection.db.collection('analytics').aggregate([]).toArray()
  }
}

MongooseService API

Property/MethodReturnsDescription
.connectionmongoose.ConnectionAccess the Mongoose connection directly
.model(name)mongoose.ModelGet a compiled model by name

All getters throw if called before app.init().

Connection lifecycle

  • onInit — connects to MongoDB via createConnection() with automatic retry on transient errors (ECONNREFUSED, ECONNRESET, ETIMEDOUT, ENOTFOUND, EAI_AGAIN), compiles all registered models
  • onDestroy — closes the connection and clears all models

Peer dependencies

PackageVersion
mongoose>= 8.0.0

Exports

import { MongooseModule, MongooseService, defineModel, InjectModel, injectModel } from '@miiajs/mongoose'
import type { MongooseModuleOptions, ModelRef } from '@miiajs/mongoose'