
Security News
Deno 2.2 Improves Dependency Management and Expands Node.js Compatibility
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
type-mongodb
Advanced tools
type-mongodb makes it easy to map classes to MongoDB documents and back using @decorators
.
@Decorator()
based document mappingtype-orm
allows you to create a base document class for common functionality. Notice
that we don't enforce strict types. MongoDB is "schema-less", so we've decided to just
support their main types and not do anything fancy. Again, we wanted to keep it as close
to the core driver as possible.
import { Id, Field } from 'type-mongodb';
import { ObjectId } from 'mongodb';
abstract class BaseDocument {
@Id()
_id: ObjectId;
get id(): string {
return this._id.toHexString();
}
@Field()
createdAt: Date = new Date();
@Field()
updatedAt: Date = new Date();
}
Now create our document class with some fields.
import { Document, Field } from 'type-mongodb';
import { BaseDocument, Address, Pet } from './models';
@Document()
class User extends BaseDocument {
@Field()
name: string;
@Field(() => Address)
address: Address; // single embedded document
@Field(() => [Address])
addresses: Address[] = []; // array of embedded documents
@Field(() => [Pet])
pets: Pet[] = []; // array of discriminator mapped documents
@Field(() => [Pet])
favoritePet: Pet = []; // single discriminator mapped document
}
And here's the embedded Address
document.
import { Field } from 'type-mongodb';
class Address {
@Field()
city: string;
@Field()
state: string;
}
type-mongodb
also has support for discriminator mapping (polymorphism). You do this
by creating a base class mapped by @Discriminator({ property: '...' })
with a @Field()
with the
name of the "property". Then decorate discriminator types with @Discriminator({ value: '...' })
and type-mongodb
takes care of the rest.
import { Discriminator, Field } from 'type-mongodb';
@Discriminator({ property: 'type' })
abstract class Pet {
@Field()
abstract type: string;
@Field()
abstract sound: string;
speak(): string {
return this.sound;
}
}
@Discriminator({ value: 'dog' })
class Dog extends Pet {
type: string = 'dog';
sound: string = 'ruff';
// dog specific fields & methods
}
@Discriminator({ value: 'cat' })
class Cat extends Pet {
type: string = 'cat';
sound: string = 'meow';
// cat specific fields & methods
}
And now, lets see the magic!
import { DocumentManager } from 'type-mongodb';
import { User } from './models';
async () => {
const dm = await DocumentManager.create({
connection: {
uri: process.env.MONGO_URI,
database: process.env.MONGO_DB
},
documents: [User]
});
const repository = dm.getRepository(User);
await repository.create({
name: 'John Doe',
address: {
city: 'San Diego',
state: 'CA'
},
addresses: [
{
city: 'San Diego',
state: 'CA'
}
],
pets: [{ type: 'dog', sound: 'ruff' }],
favoritePet: { type: 'dog', sound: 'ruff' }
});
const users = await repository.find().toArray();
};
What about custom repositories? Well, that's easy too:
import { Repository } from 'type-mongodb';
import { User } from './models';
export class UserRepository extends Repository<User> {
async findJohnDoe(): Promise<User> {
return this.findOneOrFail({ name: 'John Doe' });
}
}
Then register this repository with the User
class:
import { DocumentRepository } from 'type-mongodb';
import { UserRepository } from './repositories';
// ...
@Document({ repository: () => UserRepository })
class User extends BaseDocument {
// for type inference when using `getRepository`
[DocumentRepository]: UserRepository;
// ...
}
... and finally, to use:
const repository = dm.getRepository(User); // repository typed as UserRepository
What about custom IDs? You can either create your own type that extends Type
, or use our built-ins:
import { Id, Field, UUIDType } from 'type-mongodb';
@Document()
class User {
@Id({ type: UUIDType })
_id: string;
// fields can also be a "UUID" type.
@Field({
type: UUIDType /* create: true (pass this to auto-generate the uuid, otherwise, omit) */
})
uuid: string;
}
What about events? We want the base class to have createdAt and updatedAt be mapped correctly.
import {
EventSubscriber,
DocumentManager,
InsertEvent,
UpdateEvent
} from 'type-mongodb';
import { BaseDocument } from './models';
export class TimestampableSubscriber implements EventSubscriber<BaseDocument> {
// Find all documents that extend BaseDocument
getSubscribedDocuments?(dm: DocumentManager): any[] {
return dm
.filterMetadata(
(meta) => meta.DocumentClass.prototype instanceof BaseDocument
)
.map((meta) => meta.DocumentClass);
}
beforeInsert(e: InsertEvent<BaseDocument>) {
if (!e.model.updatedAt) {
e.model.updatedAt = new Date();
}
if (!e.model.createdAt) {
e.model.createdAt = new Date();
}
}
beforeUpdate(e: UpdateEvent<BaseDocument>) {
this.prepareUpdate(e);
}
beforeUpdateMany(e: UpdateEvent<BaseDocument>) {
this.prepareUpdate(e);
}
prepareUpdate(e: UpdateEvent<BaseDocument>) {
e.update.$set = {
updatedAt: new Date(),
...(e.update.$set || {})
};
e.update.$setOnInsert = {
createdAt: new Date(),
...(e.update.$setOnInsert || {})
};
}
}
...then register TimestampableSubscriber:
const dm = await DocumentManager.create({
/// ...,
subscribers: [TimestampableSubscriber]
});
// custom collection and database
@Document({ database: 'app', collection: 'users' })
// using internal hydration methods
dm.toDB(User, user);
dm.fromDB(User, { /* document class */ });
dm.init(User, { /* user props */ });
dm.merge(User, user, { /* user props */ });
For more advanced usage and examples, check out the tests.
FAQs
A simple decorator based MongoDB ODM.
The npm package type-mongodb receives a total of 0 weekly downloads. As such, type-mongodb popularity was classified as not popular.
We found that type-mongodb demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
Security News
React's CRA deprecation announcement sparked community criticism over framework recommendations, leading to quick updates acknowledging build tools like Vite as valid alternatives.
Security News
Ransomware payment rates hit an all-time low in 2024 as law enforcement crackdowns, stronger defenses, and shifting policies make attacks riskier and less profitable.