Last active
April 6, 2025 07:33
-
Star
(206)
You must be signed in to star a gist -
Fork
(59)
You must be signed in to fork a gist
-
-
Save brennanMKE/ee8ea002d305d4539ef6 to your computer and use it in GitHub Desktop.
Example of Mongoose with TypeScript and MongoDb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as mongoose from 'mongoose'; | |
export let Schema = mongoose.Schema; | |
export let ObjectId = mongoose.Schema.Types.ObjectId; | |
export let Mixed = mongoose.Schema.Types.Mixed; | |
export interface IHeroModel extends mongoose.Document { | |
name: string; | |
power: string; | |
amountPeopleSaved: number; | |
createdAt: Date; | |
modifiedAt: Date; | |
} | |
let schema = new Schema({ | |
name: { | |
type: String, | |
required: true | |
}, | |
power: { | |
type: String, | |
required: true | |
}, | |
amountPeopleSaved: { | |
type: Number, | |
required: false | |
}, | |
createdAt: { | |
type: Date, | |
required: false | |
}, | |
modifiedAt: { | |
type: Date, | |
required: false | |
} | |
}).pre('save', function(next) { | |
if (this._doc) { | |
let doc = <IHeroModel>this._doc; | |
let now = new Date(); | |
if (!doc.createdAt) { | |
doc.createdAt = now; | |
} | |
doc.modifiedAt = now; | |
} | |
next(); | |
return this; | |
}); | |
export let HeroSchema = mongoose.model<IHeroModel>('hero', schema, 'heroes', true); | |
export class HeroModel { | |
private _heroModel: IHeroModel; | |
constructor(heroModel: IHeroModel) { | |
this._heroModel = heroModel; | |
} | |
get name(): string { | |
return this._heroModel.name; | |
} | |
get power(): string { | |
return this._heroModel.power; | |
} | |
get amountPeopleSaved(): number { | |
return this._heroModel.amountPeopleSaved; | |
} | |
static createHero(name: string, power: string) : Promise.IThenable<IHeroModel> { | |
let p = new Promise((resolve, reject) => { | |
let repo = new HeroRepository(); | |
let hero = <IHeroModel>{ | |
name: name, | |
power: power, | |
amountPeopleSaved: 0 | |
}; | |
repo.create(hero, (err, res) => { | |
if (err) { | |
reject(err); | |
} | |
else { | |
resolve(res); | |
} | |
}); | |
}); | |
return p; | |
} | |
static findHero(name: string) : Promise.IThenable<IHeroModel> { | |
let p = new Promise((resolve, reject) => { | |
let repo = new HeroRepository(); | |
repo.find({ name : name }).sort({ createdAt: -1 }).limit(1).exec((err, res) => { | |
if (err) { | |
reject(err); | |
} | |
else { | |
if (res.length) { | |
resolve(res[0]); | |
} | |
else { | |
resolve(null); | |
} | |
} | |
}); | |
}); | |
return p; | |
} | |
} | |
Object.seal(HeroModel); | |
export interface IRead<T> { | |
retrieve: (callback: (error: any, result: any) => void) => void; | |
findById: (id: string, callback: (error: any, result: T) => void) => void; | |
findOne(cond?: Object, callback?: (err: any, res: T) => void): mongoose.Query<T>; | |
find(cond: Object, fields: Object, options: Object, callback?: (err: any, res: T[]) => void): mongoose.Query<T[]>; | |
} | |
export interface IWrite<T> { | |
create: (item: T, callback: (error: any, result: any) => void) => void; | |
update: (_id: mongoose.Types.ObjectId, item: T, callback: (error: any, result: any) => void) => void; | |
delete: (_id: string, callback: (error: any, result: any) => void) => void; | |
} | |
export class RepositoryBase<T extends mongoose.Document> implements IRead<T>, IWrite<T> { | |
private _model: mongoose.Model<mongoose.Document>; | |
constructor(schemaModel: mongoose.Model<mongoose.Document>) { | |
this._model = schemaModel; | |
} | |
create(item: T, callback: (error: any, result: T) => void) { | |
this._model.create(item, callback); | |
} | |
retrieve(callback: (error: any, result: T) => void) { | |
this._model.find({}, callback); | |
} | |
update(_id: mongoose.Types.ObjectId, item: T, callback: (error: any, result: any) => void) { | |
this._model.update({ _id: _id }, item, callback); | |
} | |
delete(_id: string, callback: (error: any, result: any) => void) { | |
this._model.remove({ _id: this.toObjectId(_id) }, (err) => callback(err, null)); | |
} | |
findById(_id: string, callback: (error: any, result: T) => void) { | |
this._model.findById(_id, callback); | |
} | |
findOne(cond?: Object, callback?: (err: any, res: T) => void): mongoose.Query<T> { | |
return this._model.findOne(cond, callback); | |
} | |
find(cond?: Object, fields?: Object, options?: Object, callback?: (err: any, res: T[]) => void): mongoose.Query<T[]> { | |
return this._model.find(cond, options, callback); | |
} | |
private toObjectId(_id: string): mongoose.Types.ObjectId { | |
return mongoose.Types.ObjectId.createFromHexString(_id); | |
} | |
} | |
export class HeroRepository extends RepositoryBase<IHeroModel> { | |
constructor() { | |
super(HeroSchema); | |
} | |
} | |
Object.seal(HeroRepository); | |
let uri = 'mongodb://localhost/heroes'; | |
mongoose.connect(uri, (err) => { | |
if (err) { | |
console.log(err.message); | |
console.log(err); | |
} | |
else { | |
console.log('Connected to MongoDb'); | |
} | |
}); | |
HeroModel.createHero('Steve', 'Flying').then((res) => { | |
console.log('### Created Hero ###'); | |
console.log(res); | |
HeroModel.findHero('Steve').then((res) => { | |
console.log('### Found Hero ###'); | |
console.log(res); | |
// now update the Hero | |
let hero = <IHeroModel>res; | |
hero.power = 'Invisibility'; | |
hero.save((err, res) => { | |
if (err) { | |
console.log(err.message); | |
console.log(err); | |
} | |
else { | |
console.log(res); | |
} | |
}); | |
}, (err) => { | |
if (err) { | |
console.log(err.message); | |
} | |
}); | |
}, (err) => { | |
if (err) { | |
console.log(err.message); | |
console.log(err); | |
} | |
}); |
For anyone stumbling on this gist, be aware that Mongoose team discourages to extend your interfaces from Mongoose.Document :
https://mongoosejs.com/docs/typescript.html#using-extends-document
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello. I fixed it by changing types using original *.ts file for mongoose. By opening the file
node_modules/@types/mongoose/index.d.ts
you can see all the required types, in the future this will help you find a solution when changing mongoose versions.findOne(cond?: Object, callback?: (err: any, res: T) => void): mongoose.Query<T> { return this._model.findOne(cond, callback); }
To
findOne(conditions?: any, callback?: (err: any, res: mongoose.Model<T> | null) => void): mongoose.DocumentQuery<T | null, T>;
You can find more examples here: https://github.com/Britskiy/BasicAppArchitecture
I've updated the dependencies and added some functionality.