Mongoose Helper
Generate Mongoose schema based on your domain model.
Enable The Functionality
MongoDB helper is optional in Plumier, it can be enabled by installing @plumier/mongoose
module and plug MongooseFacility
into Plumier application.
const plum = new Plumier()
plum.set(new MongooseFacility({uri: "mongodb://localhost:27017/test-data"}))
Mongoose facility will automatically connect to the MongoDB database and make sure it ready before application started.
Mark Domain Model For Schema Generated
Your domain model and you MongoDB collection is not 1 : 1 relation, means not all domain model will will have an appropriate MongoDB collection.
Mark domain model with @collection
decorator for auto generated schema.
import { collection } from "@plumier/mongoose"
@collection()
export class User {
constructor(
public name: string,
public image: string,
public address:string,
public city:string,
public zip:string,
) { }
}
When using
@collection()
decorator@domain()
decorator can be omitted, because@domain()
decorator actually does nothing except just to make TypeScript generate the design type information.
You don't need to specify the ID because mongoose will automatically gives you the _id
property (actually that make the domain model cleaner)
Create Model
@plumier/mongoose
provided model
function to create Mongoose model
import { model } from "@plumier/mongoose"
const UserModel = model(User)
You can create model anywhere in your code, but best practice is put them under the domain model class.
Relational Schema (populate)
If you defined relational class on your domain model, Mongoose helper will automatically generate a relation with mongoose ObjectId
@collection()
class Child {
constructor(
public name:string
){}
}
@collection()
class Parent {
constructor(
public name:string
//1 - 1 relation
public child:Child
){}
}
Using above code, mongoose facility will generate mongoose schema like below:
//child
{
name: String
}
//parent
{
name: String,
child: { type: Schema.Types.ObjectId, ref: "Parent" }
}
It also work with collection relation
@collection()
class Parent {
constructor(
public name:string
//collection relation
public children:Child[]
){}
}
//parent
{
name: String,
child: { type: [Schema.Types.ObjectId], ref: "Child" }
}
Custom Mongoose Collection Name
You can specify a name alias on @collection()
decorator to specify custom collection name. But keep in mind mongoose will pluralize your model name when creating the collection.
@collection("ParentCollection")
class Parent {
constructor(
public name:string
//collection relation
public children:Child[]
){}
}
Override Schema Generation
You can override schema generation by providing SchemaGenerator
callback on the MongooseFacility
. The signature of SchemaGenerator
is like below:
(definition:any, meta:ClassReflection) => mongoose.Schema
definition
is the object column definition generated by Plumier.meta
is the current class meta data reflection.- return instance of mongoose schema
Note that the schema generator callback will be called multiple time on each model.
Example, we will added timestamp on each of our models like example below
import Mongoose from "mongoose"
new MongooseFacility({
uri: "mongodb://localhost:27017/test-data",
schemaGenerator: (def, meta) => {
return new Mongoose.Schema(def, {timestamps: true})
}
})
Above code will apply timestamp to all models. If you want to apply to specific model, you can filter them by using metadata information.
import Mongoose from "mongoose"
new MongooseFacility({
uri: "mongodb://localhost:27017/test-data",
schemaGenerator: (def, meta) => {
if(meta.name === "Product")
return new Mongoose.Schema(def, {timestamps: true})
else
return new Mongoose.Schema(def)
}
})
Above code will only apply timestamp to domain named Product
the rest will be using default schema.
Unique Validation
Mongoose helper provided @val.unique()
that augmented (merged) with @plumier/validator
module. Means if you install @plumier/mongoose
@val
decorator will automatically has unique()
function.
This validation done some http check and only work on
POST
method, since forPUT
andPATCH
method, uniqueness check require more complex condition.
This function is not using the mongoose unique
schema, but it automatically check to the database for uniqueness, so validation engine can execute the validation rule without touching controller.
import { val } from "plumier"
@collection()
export class User {
constructor(
public name: string,
@val.unique()
public email:string,
public image: string,
public address:string,
public city:string,
public zip:string,
) { }
}
POST Form With Relational Data
Mongoose helper provided custom object converter, so it possible to post relational data from HTML Form by providing the ObjectId of the child model.
//domains
@collection()
class Image {
constructor(
public name: string
) { }
}
@collection()
class Animal {
constructor(
public name: string,
@array(Image)
public images: Image[]
) { }
}
const ImageModel = model(Image)
const AnimalModel = model(Animal)
//controller
class AnimalController {
@route.post()
async save(data: Animal) {
const newly = await new AnimalModel(data).save()
return newly._id
}
}
Above code showing that we created a route named POST /animal/save
which will save Animal information with relational data which is images data that previously saved. Below request will be valid:
POST /animal/save
payload:
{name: "Mimi", images: ["507f191e810c19729de860ea", "507f191e810c19729de239ca"]}