# Mongoose Model Conventions

# Introduction

Mongoose (opens new window) is the most popular MongoDB object modeling tool. It provides a straight-forward, schema-based solution to model your application data. It includes built-in type casting, validation, query building, business logic hooks and more, out of the box.

⚠️ Mongoose is not managed by the ExpressWebJs core team. Please, report any issues found with the library in the appropriate repository.

To get started:

1.Install the mongoose package.

  1. Install mongoose unique validator

let’s create a Users model. Models typically live in the app directory.

# Establishing Mongoose connection

Interaction with the mongoose is possible once you setup a connection. To do that update your database details in .env file located in the root directory. Let assume we are working with MySql database.

DB_CONNECTION = mongoose; //database
DB_HOST = localhost; //database host
DB_PORT = 27017; //database port
DB_USER = database_user;
DB_PASSWORD = database_password;
DB_DATABASE = database;
Copied!

You can also check database configuration file in 📘Config/database.ts. as it is reading the values in the .env file

import * as mongoose from "mongoose";
import { env, orm } from "expresswebcorets/lib/Env";
import { Path } from "expresswebcorets/lib/Utils/Path";
import { DBConnection, MongooseConfigurationType } from "expresswebcorets/lib/Database/DataSourceConfig";

export default {
  /*
  |--------------------------------------------------------------------------
  | Database ORM
  |--------------------------------------------------------------------------
  | ExpressWeb currently supports the following Object Relational Mappers(ORM)
  | Objection for sql databases and  Mongoose for mongo DB. You need to select
  | one depending on the type of database you are working on.
  |
  */
  ORM: env("ORM", orm.Mongoose),

  /*
  |--------------------------------------------------------------------------
  | Database Provider
  |--------------------------------------------------------------------------
  | With respect to the orm you selected, you need to import the provider and
  | assign it to provider.
  | Example:
  | for objection, import * as objection from "objection"
  | for typeorm, import * as typeorm from "typeorm"
  | Then assign typeorm to provider like this:
  | provider: typeorm
  |
  */
  provider: mongoose,

  /*
  |--------------------------------------------------------------------------
  | Database Multitenance
  |--------------------------------------------------------------------------
  | Database multitenance can be activated by switching the value to true and can
  | be deactivated by switching it to false.
  |
  */
  database_multitenance: env("DB_MULTITENANCE", false),
  /*
  |--------------------------------------------------------------------------
  | Multitenance Connections
  |--------------------------------------------------------------------------
  | Database multitenance connection enables interaction with multiple
  | SQL databases where each database is a tenant in your system.
  | The tenant array accepts an object of database connections (tenants).
  |
  */
  multitenant_tenants: DBConnection.multitenant<MongooseConfigurationType>("Mongoose", []),

  /*
  |--------------------------------------------------------------------------
  | Database Connection
  |--------------------------------------------------------------------------
  | Here we define connection settings for both TypeORM, Objection, and mongoose.
  | For typeORM, npm i --save typeorm
  | For Objection, npm i --save objection
  | For Mongoose, npm i --save mongoose
  | --------------------------------------------------------------------------
  | For SQL db, install the driver of your choice
  | mysql driver, npm i --save mysql mysql2
  | postgres driver, npm i --save pg pg-hstore
  |
  */
  connection: DBConnection.connect<MongooseConfigurationType>({
    client: env("DB_DRIVER"),
    connection: {
      host: env("DB_HOST"),
      port: env("DB_PORT"),
      user: env("DB_USER"),
      password: env("DB_PASSWORD"),
    },
    database: env("DB_DATABASE"),
  }),

  /*
  |--------------------------------------------------------------------------
  | Migration Configuration
  |--------------------------------------------------------------------------
  | Here we have database migration configuration.
  | Which includes the following:
  */
  migrations: {
    directory: Path("Database/Migrations/"),
    tableName: "migrations",
    stub: Path("Database/Migrations/migrationLayout.stub"),
    extension: "ts",
  },

  /*
  |--------------------------------------------------------------------------
  | Seed Configuration
  |--------------------------------------------------------------------------
  | Here we have database seed configuration.
  | Which includes the following:
  */
  seeds: {
    directory: Path("Database/Seeds/"),
  },
};
Copied!

Once that is done, we can now create our model.

The easiest way to create a nosql model instance is using the make-nosql-model command:

Now, let’s look at an example User model, which we will use to retrieve and store information from our users database table:

import { mongoose, Schema, Document } from "Elucidate/Database/NoSQLModel";
import uniqueValidator from "mongoose-unique-validator";

export interface UserInterface extends Document {
  first_name: string;
  last_name: string;
  email: string;
  password: string;
}

const UserSchema: Schema = new Schema({
  first_name: { type: String, required: true },
  first_name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true },
});

UserSchema.set("timestamps", true);
UserSchema.plugin(uniqueValidator);

const User = mongoose.model<UserInterface>("User", UserSchema);

export default User;
Copied!

# Model and Repository

To get started, let’s create a Users model. Models typically live in the App directory.

The easiest way to create a model instance is using the make-nosql-model command. If you would like to generate a database migration when you generate the model, use the m option:

Now, let’s look at an example User model, which we will use to retrieve and store information from our users database table:

import { mongoose, Schema, Document } from "Elucidate/Database/NoSQLModel";
import uniqueValidator from "mongoose-unique-validator";

export interface UserInterface extends Document {
  first_name: string;
  last_name: string;
  email: string;
  password: string;
}

const UserSchema: Schema = new Schema({
  first_name: { type: String, required: true },
  first_name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true },
});

UserSchema.set("timestamps", true);
UserSchema.plugin(uniqueValidator);

const User = mongoose.model<UserInterface>("User", UserSchema);

export default User;
Copied!

Lets create our UserRepository class in 📘App/Repository directory.

import User, { UserInterface } from "App/Model/User_model";
import { MongooseRepository } from "Elucidate/Repository/Mongoose";

export class UserRepository extends MongooseRepository<UserInterface> {
  constructor() {
    super(User);
  }
}
Copied!

We can add other methods in our repository

import User from "App/Model/User_model";
import { MongooseRepository } from "Elucidate/Repository/Mongoose";

export class UserRepository extends MongooseRepository<UserInterface> {
  constructor() {
    super(User);
  }

  async findByName(first_name: string, last_name: string) {
    return await this.findOne({ first_name, last_name });
  }
}
Copied!

Now we can use it in our UserService class in 📘App/Service/UserService directory.

import { UserRepository } from "App/Repository/UserRepository";

export class UserService {
  public async getUser(first_name: string, last_name: string): Promise<User> {
    return await new UserRepository().findByName(first_name, last_name);
  }
}
Copied!

We can also register UserRepository in AppServiceProvider and inject it in UserService

import { UserRepository } from "App/Repository/UserRepository";
import { UserService } from "App/Service/UserService";
import ServiceProvider from "Elucidate/Support/ServiceProvider";

export class AppServiceProvider extends ServiceProvider {
  /**
   * Register application services.
   * @return void
   */
  register(): Promise<void> {
    this.singleton(UserRepository);
    this.singleton(UserService);
  }
}
Copied!

We can now inject UserRepository into UserService

import { UserRepository } from "App/Repository/UserRepository";

export class UserService {
  constructor(private userRepository: UserRepository) {}

  public async getUser(first_name: string, last_name: string): Promise<User> {
    return await this.userRepository().findByName(first_name, last_name);
  }
}
Copied!