# Static Properties

# static tableName

class Person extends Model {
  static get tableName() {
    return "persons";
  }
}

Name of the database table for this model.

Each model must set this.

# static relationMappings

This property defines the relations (relationships, associations) to other models.

relationMappings is an object (or a function/getter that returns an object) whose keys are relation names and values are RelationMapping instances. The join property in addition to the relation type define how the models are related to one another.

The from and to properties of the join object define the database columns through which the models are associated. Note that neither of these columns need to be primary keys. They can be any columns. In fact they can even be fields inside JSON columns (using the ref helper). In the case of ManyToManyRelation also the join table needs to be defined. This is done using the through object.

The modelClass passed to the relation mappings is the class of the related model. It can be one of the following:

  1. A model class constructor
  2. An absolute path to a module that exports a model class
  3. A path relative to one of the paths in modelPaths array.

The file path versions are handy for avoiding require loops.

Further reading:

# Examples
const { Model, ref } = require("objection");

class Person extends Model {
  static get tableName() {
    return "persons";
  }

  static get relationMappings() {
    return {
      pets: {
        relation: Model.HasManyRelation,
        modelClass: Animal,
        join: {
          from: "persons.id",
          to: "animals.ownerId",

          // Any of the `to` and `from` fields can also be
          // references to nested fields (or arrays of references).
          // Here the relation is created between `persons.id` and
          // `animals.json.details.ownerId` properties. The reference
          // must be cast to the same type as the other key.
          //
          // to: ref('animals.json:details.ownerId').castInt()
        },
      },

      father: {
        relation: Model.BelongsToOneRelation,
        modelClass: Person,
        join: {
          from: "persons.fatherId",
          to: "persons.id",
        },
      },

      movies: {
        relation: Model.ManyToManyRelation,
        modelClass: Movie,
        join: {
          from: "persons.id",
          through: {
            from: "persons_movies.actorId",
            to: "persons_movies.movieId",

            // If you have a model class for the join table
            // you can specify it like this:
            //
            // modelClass: PersonMovie,

            // Columns listed here are automatically joined
            // to the related models on read and written to
            // the join table instead of the related table
            // on insert/update.
            //
            // extra: ['someExtra']
          },
          to: "movies.id",
        },
      },
    };
  }
}

# static idColumn

class Person extends Model {
  static get idColumn() {
    return "some_column_name";
  }
}

Name of the primary key column in the database table.

Composite id can be specified by giving an array of column names.

Defaults to 'id'.

# static jsonSchema

class Person extends Model {
  static get jsonSchema() {
    return {
      type: "object",
      required: ["name"],
      properties: {
        id: { type: "integer" },
        name: { type: "string", minLength: 1, maxLength: 255 },
        age: { type: "number" }, // optional
      },
    };
  }
}

The optional schema against which the model is validated.

Must follow JSON Schema (opens new window) specification. If unset, no validation is done.

# Read more
# Examples
class Person extends Model {
  static get jsonSchema() {
    return {
      type: "object",
      required: ["firstName", "lastName"],

      properties: {
        id: { type: "integer" },
        parentId: { type: ["integer", "null"] },
        firstName: { type: "string", minLength: 1, maxLength: 255 },
        lastName: { type: "string", minLength: 1, maxLength: 255 },
        age: { type: "number" },

        // Properties defined as objects or arrays are
        // automatically converted to JSON strings when
        // writing to database and back to objects and arrays
        // when reading from database. To override this
        // behaviour, you can override the
        // Person.jsonAttributes property.
        address: {
          type: "object",
          properties: {
            street: { type: "string" },
            city: { type: "string" },
            zipCode: { type: "string" },
          },
        },
      },
    };
  }
}

# static virtualAttributes

class Person extends Model {
  static get virtualAttributes() {
    return ["fullName", "isFemale"];
  }

  fullName() {
    return `${this.firstName} ${this.lastName}`;
  }

  get isFemale() {
    return this.gender === "female";
  }
}

Getters and methods listed here are serialized with real properties when toJSON is called. Virtual attribute methods and getters must be synchronous.

The virtual values are not written to database. Only the "external" JSON format will contain them.

# Examples
class Person extends Model {
  static get virtualAttributes() {
    return ["fullName", "isFemale"];
  }

  fullName() {
    return `${this.firstName} ${this.lastName}`;
  }

  get isFemale() {
    return this.gender === "female";
  }
}

const person = Person.fromJson({
  firstName: "Jennifer",
  lastName: "Aniston",
  gender: "female",
});

// Note that `toJSON` is always called automatically
// when an object is serialized to a JSON string using
// JSON.stringify. You very rarely need to call `toJSON`
// explicitly. koa, express and all other frameworks I'm
// aware of use JSON.stringify to serialize objects to JSON.
const pojo = person.toJSON();

console.log(pojo.fullName); // --> 'Jennifer Aniston'
console.log(pojo.isFemale); // --> true

You can also pass options to toJSON to only serialize a subset of virtual attributes. In fact, when the virtuals option is used, the attributes don't even need to be listed in virtualAttributes.

const pojo = person.toJSON({ virtuals: ["fullName"] });

# static modifiers

Reusable query building functions that can be used in any query using modify method and in many other places.

class Movie extends Model {
  static get modifiers() {
    return {
      goodMovies(builder) {
        builder.where("stars", ">", 3);
      },

      orderByName(builder) {
        builder.orderBy("name");
      },
    };
  }
}

class Animal extends Model {
  static get modifiers() {
    return {
      dogs(builder) {
        builder.where("species", "dog");
      },
    };
  }
}

Modifiers can be used for relations in a withGraphFetched or withGraphJoined query.

Person.query().withGraphFetched(
  "[movies(goodMovies, orderByName).actors, pets(dogs)]"
);

Modifiers can also be used through modifyGraph:

Person.query()
  .withGraphFetched("[movies.actors, pets]")
  .modifyGraph("movies", ["goodMovies", "orderByName"])
  .modifyGraph("pets", "dogs");

# static namedFilters

WARNING

Deprecated! Will be removed in version 3.0. Use modifiers instead.

v1 documentation (opens new window)

An alias for modifiers

# static modelPaths

class Person extends Model {
  static get modelPaths() {
    return [__dirname];
  }
}

A list of paths from which to search for models for relations.

A model class can be defined for a relation in relationMappings as

  1. A model class constructor
  2. An absolute path to a module that exports a model class
  3. A path relative to one of the paths in modelPaths array.

You probably don't want to define modelPaths property for each model. Once again we recommend that you create a BaseModel super class for all your models and define shared configuration such as this there.

# Examples

Using a shared BaseModel superclass:

const { Model } = require('objection');

// models/BaseModel.js
class BaseModel extends Model {
  static get modelPaths() {
    return [__dirname];
  }
}

module.exports = {
  BaseModel
};

// models/Person.js
const { BaseModel } = require('./BaseModel');

class Person extends BaseModel {
  ...
}

# static concurrency

class Person extends Model {
  static get concurrency() {
    return 10;
  }
}

How many queries can be run concurrently per connection.

This doesn't limit the concurrency of the entire server. It only limits the number of concurrent queries that can be run on a single connection. By default knex connection pool size is 10, which means that the maximum number of concurrent queries started by ExpressWeb JS is Model.concurrency * 10. You can also easily increase the knex pool size.

The default concurrency is 4 except for mssql, for which the default is 1. The mssql default is needed because of the buggy driver that only allows one query at a time per connection.

# static jsonAttributes

class Person extends Model {
  static get jsonAttributes() {
    return ["someProp", "someOtherProp"];
  }
}

Properties that should be saved to database as JSON strings.

The properties listed here are serialized to JSON strings upon insertion/update to the database and parsed back to objects when models are read from the database. Combined with the postgresql's json or jsonb data type, this is a powerful way of representing documents as single database rows.

If this property is left unset all properties declared as objects or arrays in the jsonSchema are implicitly added to this list.

# static cloneObjectAttributes

class Person extends Model {
  static get cloneObjectAttributes() {
    return false;
  }
}

If true (the default) object attributes (for example jsonb columns) are cloned when $toDatabaseJson, $toJson or toJSON is called. If this is set to false, they are not cloned. Note that nested Model instances inside relations etc. are still effectively cloned, because $toJson is called for them recursively, but their jsonb columns, again, are not 😃

Usually you don't need to care about this setting, but if you have large object fields (for example large objects in jsonb columns) cloning the data can become slow and play a significant part in your server's performance. There's rarely a need to to clone this data, but since it has historically been copied, we cannot change the default behaviour easily.

TLDR; Set this setting to false if you have large jsonb columns and you see that cloning that data takes a significant amount of time when you profile the code.

# static columnNameMappers

const { Model, snakeCaseMappers } = require("objection");

class Person extends Model {
  static get columnNameMappers() {
    return snakeCaseMappers();
  }
}

The mappers to use to convert column names to property names in code.

Further reading:

  • snakeCaseMappers
  • snake_case to camelCase conversion recipe
# Examples

If your columns are UPPER_SNAKE_CASE:

const { Model, snakeCaseMappers } = require("objection");

class Person extends Model {
  static get columnNameMappers() {
    return snakeCaseMappers({ upperCase: true });
  }
}

The mapper signature:

class Person extends Model {
  static columnNameMappers = {
    parse(obj) {
      // database --> code
    },

    format(obj) {
      // code --> database
    },
  };
}

# static relatedFindQueryMutates

WARNING

Deprecated! Will be removed in version 3.0.

v1 documentation (opens new window)

class Person extends Model {
  static get relatedFindQueryMutates() {
    return false;
  }
}

If this config is set to false, calling foo.$relatedQuery('bar') doesn't assign the fetched related models to foo.bar. The default is false.

# static relatedInsertQueryMutates

WARNING

Deprecated! Will be removed in version 3.0.

v1 documentation (opens new window)

class Person extends Model {
  static get relatedInsertQueryMutates() {
    return false;
  }
}

If this config is set to false, calling foo.$relatedQuery('bar').insert(obj) doesn't append the inserted related model to foo.bar. The default is false.

# static uidProp

class Person extends Model {
  static get uidProp() {
    return "#id";
  }
}

Name of the property used to store a temporary non-db identifier for the model.

NOTE: You cannot use any of the model's properties as uidProp. For example if your model has a property id, you cannot set uidProp = 'id'.

Defaults to '#id'.

# static uidRefProp

class Person extends Model {
  static get uidRefProp() {
    return "#ref";
  }
}

Name of the property used to store a reference to a uidProp

NOTE: You cannot use any of the model's properties as uidRefProp. For example if your model has a property ref, you cannot set uidRefProp = 'ref'.

Defaults to '#ref'.

# static dbRefProp

class Person extends Model {
  static get dbRefProp() {
    return "#dbRef";
  }
}

Name of the property used to point to an existing database row from an insertGraph graph.

NOTE: You cannot use any of the model's properties as dbRefProp. For example if your model has a property id, you cannot set dbRefProp = 'id'.

Defaults to '#dbRef'.

# static propRefRegex

class Person extends Model {
  static get propRefRegex() {
    return /#ref{([^\.]+)\.([^}]+)}/g;
  }
}

Regular expression for parsing a reference to a property.

Defaults to /#ref{([^\.]+)\.([^}]+)}/g.

# static pickJsonSchemaProperties

class Person extends Model {
  static get pickJsonSchemaProperties() {
    return true;
  }
}

If this is true only properties in jsonSchema are picked when inserting or updating a row in the database.

Defaults to false.

# static defaultEagerAlgorithm

WARNING

Deprecated! Will be removed in version 3.0. Use withGraphFetched or withGraphJoined explicitly.

v1 documentation (opens new window)

# static defaultEagerOptions

WARNING

Deprecated! Will be removed in version 3.0. Use defaultGraphOptions instead.

v1 documentation (opens new window)

# static defaultGraphOptions

class Person extends Model {
  static get defaultGraphOptions() {
    return {
      minimize: true,
      separator: "->",
      aliases: {},
      maxBatchSize: 10000,
    };
  }
}

Sets the default options for withGraphFetched and withGraphJoined. See the possible fields here.

Defaults to { minimize: false, separator: ':', aliases: {}, maxBatchSize: 10000 }.

# static useLimitInFirst

class Animal extends Model {
  static get useLimitInFirst() {
    return true;
  }
}

If true, limit(1) is added to the query when first() is called. Defaults to false for legacy reasons.

# static QueryBuilder

class Person extends Model {
  static get QueryBuilder() {
    return MyCustomQueryBuilder;
  }
}

QueryBuilder subclass to use for all queries created for this model.

This constructor is used whenever a query builder is created using query, $query, $relatedQuery or any other method that creates a query. You can override this to use your own QueryBuilder subclass.

# static BelongsToOneRelation

class Person extends Model {
  static get relationMappings() {
    parent: {
      relation: Model.BelongsToOneRelation,
      ...
    }
  }
}

A relation type that can be used in relationMappings to create a belongs-to-one relationship.

# static HasOneRelation

class Person extends Model {
  static get relationMappings() {
    parent: {
      relation: Model.HasOneRelation,
      ...
    }
  }
}

A relation type that can be used in relationMappings to create a has-one relationship.

# static HasManyRelation

class Person extends Model {
  static get relationMappings() {
    pets: {
      relation: Model.HasManyRelation,
      ...
    }
  }
}

A relation type that can be used in relationMappings to create a has-may relationship.

# static ManyToManyRelation

class Person extends Model {
  static get relationMappings() {
    movies: {
      relation: Model.ManyToManyRelation,
      ...
    }
  }
}

A relation type that can be used in relationMappings to create a many-to-many relationship.

# static HasOneThroughRelation

class Person extends Model {
  static get relationMappings() {
    favoriteMovie: {
      relation: Model.HasOneThroughRelation,
      ...
    }
  }
}

A relation type that can be used in relationMappings to create a has-one-through relationship.