Menu

BaseModel API Reference

The BaseModel class is the foundation of all models in Adonis ODM. It provides the core functionality for interacting with MongoDB documents.

Class Definition

abstract class BaseModel {
  // Static properties
  static table: string
  static connection: string
  static primaryKey: string

  // Instance properties
  $attributes: Record<string, any>
  $original: Record<string, any>
  $dirty: Record<string, any>
  $isLocal: boolean
  $isPersisted: boolean
  $isDeleted: boolean
}

Static Properties

table

The MongoDB collection name for the model.

export default class User extends BaseModel {
  static table = 'users'
}

Default: Pluralized, snake_case version of the model name

connection

The database connection to use for this model.

export default class User extends BaseModel {
  static connection = 'mongodb'
}

Default: The default connection from config

primaryKey

The primary key field name.

export default class User extends BaseModel {
  static primaryKey = '_id'
}

Default: '_id'

Static Methods

query(options?)

Create a new query builder instance.

static query(options?: QueryOptions): ModelQueryBuilder<Model>

Parameters:

  • options.client? - Transaction client to use

Returns: ModelQueryBuilder<Model>

Example:

const users = await User.query().where('isActive', true).all()

create(attributes, options?)

Create and save a new model instance.

static async create<T extends BaseModel>(
  this: ModelConstructor<T>,
  attributes: Partial<ModelAttributes<T>>,
  options?: SaveOptions
): Promise<T>

Parameters:

  • attributes - The model attributes
  • options.client? - Transaction client to use

Returns: Promise<Model>

Example:

const user = await User.create({
  name: 'John Doe',
  email: '[email protected]'
})

createMany(attributesArray, options?)

Create multiple model instances.

static async createMany<T extends BaseModel>(
  this: ModelConstructor<T>,
  attributesArray: Partial<ModelAttributes<T>>[],
  options?: SaveOptions
): Promise<T[]>

Example:

const users = await User.createMany([
  { name: 'John', email: '[email protected]' },
  { name: 'Jane', email: '[email protected]' }
])

find(id, options?)

Find a model by its primary key.

static async find<T extends BaseModel>(
  this: ModelConstructor<T>,
  id: any,
  options?: QueryOptions
): Promise<T | null>

Example:

const user = await User.find('507f1f77bcf86cd799439011')

findOrFail(id, options?)

Find a model by its primary key or throw an exception.

static async findOrFail<T extends BaseModel>(
  this: ModelConstructor<T>,
  id: any,
  options?: QueryOptions
): Promise<T>

Throws: ModelNotFoundException if not found

findBy(field, value, options?)

Find a model by a specific field.

static async findBy<T extends BaseModel>(
  this: ModelConstructor<T>,
  field: string,
  value: any,
  options?: QueryOptions
): Promise<T | null>

Example:

const user = await User.findBy('email', '[email protected]')

findByOrFail(field, value, options?)

Find a model by a specific field or throw an exception.

static async findByOrFail<T extends BaseModel>(
  this: ModelConstructor<T>,
  field: string,
  value: any,
  options?: QueryOptions
): Promise<T>

first(options?)

Get the first model from the collection.

static async first<T extends BaseModel>(
  this: ModelConstructor<T>,
  options?: QueryOptions
): Promise<T | null>

firstOrFail(options?)

Get the first model from the collection or throw an exception.

static async firstOrFail<T extends BaseModel>(
  this: ModelConstructor<T>,
  options?: QueryOptions
): Promise<T>

all(options?)

Get all models from the collection.

static async all<T extends BaseModel>(
  this: ModelConstructor<T>,
  options?: QueryOptions
): Promise<T[]>

updateOrCreate(search, attributes, options?)

Update an existing model or create a new one.

static async updateOrCreate<T extends BaseModel>(
  this: ModelConstructor<T>,
  search: Partial<ModelAttributes<T>>,
  attributes: Partial<ModelAttributes<T>>,
  options?: SaveOptions
): Promise<T>

Example:

const user = await User.updateOrCreate(
  { email: '[email protected]' },
  { name: 'John Doe', isActive: true }
)

truncate(options?)

Remove all documents from the collection.

static async truncate<T extends BaseModel>(
  this: ModelConstructor<T>,
  options?: QueryOptions
): Promise<void>

Instance Properties

$attributes

The current model attributes.

readonly $attributes: Record<string, any>

$original

The original model attributes (before changes).

readonly $original: Record<string, any>

$dirty

The changed attributes since last save.

readonly $dirty: Record<string, any>

$isLocal

Whether the model exists only in memory (not saved to database).

readonly $isLocal: boolean

$isPersisted

Whether the model has been saved to the database.

readonly $isPersisted: boolean

$isDeleted

Whether the model has been deleted.

readonly $isDeleted: boolean

Instance Methods

save(options?)

Save the model to the database.

async save(options?: SaveOptions): Promise<this>

Parameters:

  • options.client? - Transaction client to use

Example:

const user = new User()
user.name = 'John Doe'
user.email = '[email protected]'
await user.save()

delete(options?)

Delete the model from the database.

async delete(options?: QueryOptions): Promise<void>

refresh(options?)

Reload the model from the database.

async refresh(options?: QueryOptions): Promise<this>

fill(attributes)

Fill the model with attributes.

fill(attributes: Partial<ModelAttributes<this>>): this

Example:

const user = new User()
user.fill({
  name: 'John Doe',
  email: '[email protected]'
})

merge(attributes)

Merge attributes into the model.

merge(attributes: Partial<ModelAttributes<this>>): this

toJSON()

Convert the model to a plain JavaScript object.

toJSON(): Record<string, any>

serialize(cherryPick?)

Serialize the model with optional field selection.

serialize(cherryPick?: CherryPick): Record<string, any>

Parameters:

  • cherryPick.fields.pick? - Fields to include
  • cherryPick.fields.omit? - Fields to exclude

Example:

// Include only specific fields
const json = user.serialize({
  fields: {
    pick: ['name', 'email']
  }
})

// Exclude specific fields
const json = user.serialize({
  fields: {
    omit: ['password']
  }
})

Hooks

Models support various lifecycle hooks:

@beforeSave()

Called before saving (create or update).

@beforeSave()
static async hashPassword(user: User) {
  if (user.$dirty.password) {
    user.password = await Hash.make(user.password)
  }
}

@afterSave()

Called after saving (create or update).

@beforeCreate()

Called before creating a new model.

@afterCreate()

Called after creating a new model.

@beforeUpdate()

Called before updating an existing model.

@afterUpdate()

Called after updating an existing model.

@beforeDelete()

Called before deleting a model.

@afterDelete()

Called after deleting a model.

Types

ModelConstructor<T>

Type for model constructor.

type ModelConstructor<T extends BaseModel> = {
  new (): T
  // ... static methods
}

ModelAttributes<T>

Type for model attributes.

type ModelAttributes<T extends BaseModel> = {
  [K in keyof T]: T[K]
}

SaveOptions

Options for save operations.

interface SaveOptions {
  client?: TransactionClient
}

QueryOptions

Options for query operations.

interface QueryOptions {
  client?: TransactionClient
}

CherryPick

Options for selective serialization.

interface CherryPick {
  fields?: {
    pick?: string[]
    omit?: string[]
  }
}

Examples

Basic CRUD Operations

// Create
const user = await User.create({
  name: 'John Doe',
  email: '[email protected]'
})

// Read
const foundUser = await User.find(user._id)
const userByEmail = await User.findBy('email', '[email protected]')

// Update
user.name = 'John Smith'
await user.save()

// Delete
await user.delete()

Working with Hooks

export default class User extends BaseModel {
  @column()
  declare email: string

  @column()
  declare password: string

  @beforeSave()
  static async normalizeEmail(user: User) {
    if (user.$dirty.email) {
      user.email = user.email.toLowerCase().trim()
    }
  }

  @beforeCreate()
  static async hashPassword(user: User) {
    if (user.password) {
      user.password = await Hash.make(user.password)
    }
  }
}

Custom Methods

export default class User extends BaseModel {
  @column()
  declare isActive: boolean

  // Instance method
  async activate() {
    this.isActive = true
    await this.save()
  }

  // Static method
  static async getActiveUsers() {
    return this.query().where('isActive', true).all()
  }
}

Next Steps