Plumier

Plumier

  • Docs
  • Tutorials
  • GitHub

›References

Fundamentals

  • Plumier In Five Minutes
  • Application Startup
  • Controller
  • ActionResult
  • Middleware
  • Facility

References

  • Route Cheat Sheet
  • Parameter Binding
  • Validation
  • Converters
  • Authorization
  • Error Handling
  • Serve Static Files
  • File Upload
  • Mongoose Helper
  • Social Login
  • Controller Invoker
  • Static Analysis
  • Testing Tips

Extending

  • Custom Parameter Binding
  • Custom Validator
  • Custom Authorization

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 for PUT and PATCH 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"]}
← File UploadSocial Login →
  • Enable The Functionality
  • Mark Domain Model For Schema Generated
  • Create Model
  • Relational Schema (populate)
  • Custom Mongoose Collection Name
  • Override Schema Generation
  • Unique Validation
  • POST Form With Relational Data
Copyright © 2019 Plumier