# 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:
- A model class constructor
- An absolute path to a module that exports a model class
- A path relative to one of the paths in modelPaths array.
The file path versions are handy for avoiding require loops.
Further reading:
- the relation guide
- RelationMapping
# 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
- $validate
- jsonAttributes
- custom validation recipe
# 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.
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
- A model class constructor
- An absolute path to a module that exports a model class
- 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
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
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.
# static
defaultEagerOptions
WARNING
Deprecated! Will be removed in version 3.0. Use defaultGraphOptions
instead.
# 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.