@cpbs-cp/mongoose
v1.0.14
Published
CPBS abstraction layer over Mongoose. Shields applications from breaking Mongoose API changes.
Maintainers
Readme
@vetrivelan-cp/mongoose
CPBS abstraction layer over Mongoose — no @nestjs/mongoose dependency.
Drop-in replacement for @nestjs/mongoose. All existing application code that uses
MongooseModule.forRoot, MongooseModule.forFeature, @InjectModel, @InjectConnection
works without any changes — just update the import path.
Installation
npm i @vetrivelan-cp/mongoosePeer dependencies
npm i mongoose reflect-metadata| Peer | Version | Required |
|------|---------|----------|
| mongoose | ^6 \|\| ^7 \|\| ^8 | ✅ Yes |
| reflect-metadata | ^0.1.13 \|\| ^0.2.0 | ✅ Yes |
| @nestjs/common | ^9 \|\| ^10 | optional |
No
@nestjs/mongooserequired — that is the whole point of this package.
NestJS usage (old code works unchanged)
1. Connect — AppModule
// app.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@vetrivelan-cp/mongoose';
@Module({
imports: [
MongooseModule.forRoot(process.env.MONGODB_URI), // returns DynamicModule ✓
// ... feature modules
],
})
export class AppModule {}Or with async factory (e.g. ConfigService):
MongooseModule.forRootAsync({
imports: [ConfigModule],
useFactory: (cfg: ConfigService) => ({ uri: cfg.get('MONGODB_URI') }),
inject: [ConfigService],
})Named connection (multi-DB):
MongooseModule.forRootAsync({
connectionName: 'mms',
useFactory: async () => ({ uri: process.env.MMS_URI }),
})2. Register models — feature module (unchanged)
// dynamic-qr.module.ts
import { forwardRef, Module } from '@nestjs/common';
import { MongooseModule } from '@vetrivelan-cp/mongoose';
import { DynamicQr, DynamicQrSchema } from './schema/dynamic-qr.schema';
import { DynamicQrService } from './dynamic-qr.service';
import { DynamicQrController } from './dynamic-qr.controller';
@Module({
imports: [
MongooseModule.forFeature([ // returns DynamicModule ✓
{ name: DynamicQr.name, schema: DynamicQrSchema },
]),
forwardRef(() => OtherModule),
],
controllers: [DynamicQrController],
providers: [DynamicQrService],
exports: [DynamicQrService],
})
export class DynamicQrModule {}Named connection:
MongooseModule.forFeature(
[{ name: Merchant.name, schema: MerchantSchema }],
'mms', // <-- connection name
)3. Define a schema (unchanged)
// user.schema.ts
import { Schema, Prop, SchemaFactory, CpbsDocument } from '@vetrivelan-cp/mongoose';
@Schema({ timestamps: true, collection: 'users' })
export class User {
@Prop({ required: true })
userName!: string;
@Prop({ required: true })
email!: string;
@Prop({ default: true })
isActive!: boolean;
}
export const UserSchema = SchemaFactory.createForClass(User);
export type UserDocument = CpbsDocument<User>;4. Inject model into service (unchanged)
// user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel, Model, CpbsDocument } from '@vetrivelan-cp/mongoose';
import { User } from './user.schema';
@Injectable()
export class UserService {
constructor(
@InjectModel(User.name)
private readonly userModel: Model<CpbsDocument<User>>,
) {}
async create(data: Partial<User>) {
return this.userModel.create(data);
}
async findAll() {
return this.userModel.find().lean();
}
async findById(id: string) {
return this.userModel.findById(id).lean();
}
async update(id: string, data: Partial<User>) {
return this.userModel.findByIdAndUpdate(id, data, { new: true });
}
async delete(id: string) {
return this.userModel.findByIdAndDelete(id);
}
}5. Inject connection
import { Injectable } from '@nestjs/common';
import { InjectConnection, Connection } from '@vetrivelan-cp/mongoose';
@Injectable()
export class DbHealthService {
constructor(
@InjectConnection()
private readonly connection: Connection,
) {}
getStatus() {
return this.connection.readyState; // 1 = connected
}
}Named connection:
@InjectConnection('mms') private readonly mmsConn: Connection6. Extend BaseRepository
import { Injectable } from '@nestjs/common';
import { InjectModel, BaseRepository, Model, CpbsDocument } from '@vetrivelan-cp/mongoose';
import { User } from './user.schema';
@Injectable()
export class UserRepository extends BaseRepository<CpbsDocument<User>> {
constructor(
@InjectModel(User.name)
model: Model<CpbsDocument<User>>,
) {
super(model);
}
async findByEmail(email: string) {
return this.model.findOne({ email }).lean();
}
}Migration from @nestjs/mongoose
| Before | After |
|--------|-------|
| import { MongooseModule } from '@nestjs/mongoose' | import { MongooseModule } from '@vetrivelan-cp/mongoose' |
| import { InjectModel } from '@nestjs/mongoose' | import { InjectModel } from '@vetrivelan-cp/mongoose' |
| import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose' | import { Schema, Prop, SchemaFactory } from '@vetrivelan-cp/mongoose' |
| MongooseModule.forRoot(...) in imports:[] | ✅ Same — works unchanged |
| MongooseModule.forFeature([...]) in imports:[] | ✅ Same — works unchanged |
| @InjectModel(X.name) | ✅ Same — works unchanged |
| @InjectConnection() | ✅ Same — works unchanged |
Just replace the import source — nothing else changes.
API reference
MongooseModule
| Method | Returns | Use in |
|--------|---------|--------|
| forRoot(uri, options?) | DynamicModule | imports: [] |
| forRootAsync(options) | DynamicModule | imports: [] |
| forFeature(models, connectionName?) | DynamicModule | imports: [] |
| close(name?) | Promise<void> | onModuleDestroy / tests |
getConnection(name?)
Retrieve a raw Mongoose Connection outside of NestJS DI:
import { getConnection } from '@vetrivelan-cp/mongoose';
const conn = getConnection(); // default connection
const mms = getConnection('mms'); // named connectionDecorators
| Export | Description |
|--------|-------------|
| @Schema(options?) | Marks a class as a Mongoose schema |
| @Prop(options?) | Defines a field on the schema |
| SchemaFactory.createForClass(cls) | Builds mongoose.Schema from a decorated class |
Injection token helpers
import { InjectModel, InjectConnection } from '@vetrivelan-cp/mongoose';
InjectModel('User') // → 'UserModel'
InjectModel('User', 'mms') // → 'mmsConnection/UserModel'
InjectConnection() // → 'DatabaseConnection'
InjectConnection('mms') // → 'mmsConnection'Utility functions
| Export | Description |
|--------|-------------|
| getModelToken(model, connectionName?) | Returns provider token for a model |
| getConnectionToken(name?) | Returns provider token for a connection |
| handleRetry(fn, attempts?, delay?, verbose?) | Retry a Promise-returning factory |
| raw(definition) | Pass-through raw schema definition |
Types
import {
CpbsDocument, // HydratedDocument<T>
ObjectId, // mongoose.Types.ObjectId
toObjectId, // (id: string) => ObjectId
FilterQuery,
UpdateQuery,
QueryOptions,
ProjectionType,
PipelineStage,
UpdateWithAggregationPipeline,
SaveOptions,
AggregateOptions,
Model,
Connection,
Document,
Types,
SchemaTypes,
mongoose, // raw mongoose namespace
MixedType,
Mixed,
} from '@vetrivelan-cp/mongoose';Scripts
| Command | Description |
|---------|-------------|
| npm run build | Compile TypeScript → dist/ |
| npm run build:watch | Build in watch mode |
| npm test | Run all unit tests |
| npm run test:watch | Tests in watch mode |
| npm run test:cov | Tests with coverage report |
Publishing
npm run prepublishOnly # runs tests → build → strips tsbuildinfoLicense
MIT
