# Instance Methods
All instance methods start with the character $ to prevent them from colliding with the database column names.
# $query()
const queryBuilder = person.$query(transactionOrKnex);
Creates a query builder for this model instance.
All queries built using the returned builder only affect this instance.
# Arguments
| Argument | Type | Description |
|---|---|---|
| transactionOrKnex | object | Optional transaction or knex instance for the query. This can be used to specify a transaction or even a different database for a query. Falsy values are ignored. |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | query builder |
# Examples
Re-fetch an item from the database:
// If you need to refresh the same instance you can do this:
const reFetchedPerson = await person.$query();
// Note that `person` did not get modified by the fetch.
person.$set(reFetchedPerson);
Insert a new item to database:
const jennifer = await Person.fromJson({ firstName: 'Jennifer' })
.$query()
.insert();
console.log(jennifer.id);
Patch an item:
await person.$query().patch({ lastName: 'Cooper' });
console.log('person updated');
Delete an item.
await person.$query().delete();
console.log('person deleted');
# $relatedQuery()
const builder = person.$relatedQuery(relationName, transactionOrKnex);
Use this to build a query that only affects items related through a relation.
See the examples below and here.
TIP
This methods is just a shortcut for this call to the static relatedQuery method:
const builder = Person.relatedQuery(relationName, transactionOrKnex).for(
person
);
# Arguments
| Argument | Type | Description |
|---|---|---|
| relationName | string | The name of the relation to query. |
| transactionOrKnex | object | Optional transaction or knex instance for the query. This can be used to specify a transaction or even a different database for a query. Falsy values are ignored. |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | A query builder |
# Examples
Fetch all items related to an item through a relation:
const pets = await jennifer.$relatedQuery('pets');
console.log('jennifer has', pets.length, 'pets');
The related query is just like any other query. All knex and objection query builder methods are available:
const dogsAndCats = await jennifer
.$relatedQuery('pets')
.select('animals.*', 'persons.name as ownerName')
.where('species', '=', 'dog')
.orWhere('breed', '=', 'cat')
.innerJoin('persons', 'persons.id', 'animals.ownerId')
.orderBy('animals.name');
// All the dogs and cats have the owner's name "Jennifer"
// joined as the `ownerName` property.
console.log(dogsAndCats);
This inserts a new item to the database and binds it to the owner item as defined by the relation (by default):
const waldo = await jennifer
.$relatedQuery('pets')
.insert({ species: 'dog', name: 'Fluffy' });
console.log(waldo.id);
To attach an existing item to a relation the relate method can be used. In this example the dog fluffy already exists in the database but it isn't related to jennifer through the pets relation. We can make the connection like this:
await jennifer.$relatedQuery('pets').relate(fluffy.id);
console.log('fluffy is now related to jennifer through pets relation');
The connection can be removed using the unrelate method. Again, this doesn't delete the related model. Only the connection is removed. For example in the case of ManyToMany relation the join table entries are deleted.
await jennifer
.$relatedQuery('pets')
.unrelate()
.where('id', fluffy.id);
console.log('jennifer no longer has fluffy as a pet');
Related items can be deleted using the delete method. Note that in the case of ManyToManyRelation the join table entries are not deleted. You should use ON DELETE CASCADE in your database migrations to make the database properly delete the join table rows when either end of the relation is deleted. Naturally the delete query can be chained with any query building methods.
await jennifer
.$relatedQuery('pets')
.delete()
.where('species', 'cat');
console.log('jennifer no longer has any cats');
update and patch can be used to update related models. Only difference between the mentioned methods is that update validates the input objects using the related model class's full schema and patch ignores the required property of the schema. Use update when you want to update all properties of a model and patch when only a subset should be updated.
const updatedFluffy = await jennifer
.$relatedQuery('pets')
.update({ species: 'dog', name: 'Fluffy the great', vaccinated: false })
.where('id', fluffy.id);
console.log("fluffy's new name is", updatedFluffy.name);
// This query will be rejected assuming that `name` or `species`
// is a required property for an Animal.
await jennifer
.$relatedQuery('pets')
.update({ vaccinated: true })
.where('species', 'dog');
// This query will succeed.
await jennifer
.$relatedQuery('pets')
.patch({ vaccinated: true })
.where('species', 'dog');
console.log('jennifer just got all her dogs vaccinated');
# $beforeInsert()
class Person extends Model {
async $beforeInsert(queryContext) {
await super.$beforeInsert(queryContext);
await this.doPossiblyAsyncStuff();
}
}
Called before a model is inserted into the database.
You can return a promise from this function if you need to do asynchronous stuff. You can also throw an exception to abort the insert and reject the query. This can be useful if you need to do insert specific validation.
If you start a query from this hook, make sure you specify queryContext.transaction as it's connection to make sure the query takes part in the same transaction as the parent query. See the example below.
# Arguments
| Argument | Type | Description |
|---|---|---|
| queryContext | Object | The context object of the insert query. See context. |
# Return value
| Type | Description |
|---|---|
| Promise (opens new window) void | Promise or void depending whether your hook is async or not. |
# Examples
The current query's transaction/knex instance can always be accessed through queryContext.transaction.
class Person extends Model {
async $beforeInsert(queryContext) {
await super.$beforeInsert(queryContext);
// This can always be done even if there is no running
// transaction. In that case `queryContext.transaction`
// returns the normal knex instance. This makes sure that
// the query is not executed outside the original query's
// transaction.
await SomeModel.query(queryContext.transaction).insert(whatever);
}
}
# $afterInsert()
class Person extends Model {
async $afterInsert(queryContext) {
await super.$afterInsert(queryContext);
await this.doPossiblyAsyncStuff();
}
}
Called after a model has been inserted into the database.
You can return a promise from this function if you need to do asynchronous stuff.
# Arguments
| Argument | Type | Description |
|---|---|---|
| queryContext | Object | The context object of the insert query. See context. |
# Return value
| Type | Description |
|---|---|
| Promise (opens new window) void | Promise or void depending whether your hook is async or not. |
# Examples
The current query's transaction/knex instance can always be accessed through queryContext.transaction.
class Person extends Model {
async $afterInsert(queryContext) {
await super.$afterInsert(queryContext);
// This can always be done even if there is no running transaction. In that
// case `queryContext.transaction` returns the normal knex instance. This
// makes sure that the query is not executed outside the original query's
// transaction.
await SomeModel.query(queryContext.transaction).insert(whatever);
}
}
# $beforeUpdate()
class Person extends Model {
async $beforeUpdate(opt, queryContext) {
await super.$beforeUpdate(opt, queryContext);
await this.doPossiblyAsyncStuff();
}
}
Called before a model instance is updated.
You can return a promise from this function if you need to do asynchronous stuff. You can also throw an exception to abort the update and reject the query. This can be useful if you need to do update specific validation.
This method is also called before a model is patched. Therefore all the model's properties may not exist. You can check if the update operation is a patch by checking the opt.patch boolean.
Inside the hook, this contains the values to be updated. If (and only if) the query is started for an existing model instance using $query, opt.old object contains the old values. The old values are never fetched from the database implicitly. For non-instance queries the opt.old object is undefined. See the examples.
# Arguments
| Argument | Type | Description |
|---|---|---|
| opt | ModelOptions | Update options. |
| queryContext | Object | The context object of the update query. See context. |
# Return value
| Type | Description |
|---|---|
| Promise (opens new window) void | Promise or void depending whether your hook is async or not. |
# Examples
The current query's transaction/knex instance can always be accessed through queryContext.transaction.
class Person extends Model {
async $beforeUpdate(opt, queryContext) {
await super.$beforeUpdate(opt, queryContext);
// This can always be done even if there is no running transaction.
// In that case `queryContext.transaction` returns the normal knex
// instance. This makes sure that the query is not executed outside
// the original query's transaction.
await SomeModel.query(queryContext.transaction).insert(whatever);
}
}
Note that the opt.old object is only populated for instance queries started with $query:
somePerson.$query().update(newValues);
For the following query opt.old is undefined because there is no old object in the JavaScript side. objection.js doesn't fetch the old values even if they existed in the database
for performance and simplicity reasons.
Person.query()
.update(newValues)
.where('foo', 'bar');
# $afterUpdate()
class Person extends Model {
async $afterUpdate(opt, queryContext) {
await super.$afterUpdate(opt, queryContext);
await this.doPossiblyAsyncStuff();
}
}
Called after a model instance is updated.
You can return a promise from this function if you need to do asynchronous stuff.
This method is also called after a model is patched. Therefore all the model's properties may not exist. You can check if the update operation is a patch by checking the opt.patch boolean.
Inside the hook, this contains the values to be updated. If (and only if) the query is started for an existing model instance using $query, opt.old object contains the old values. The old values are never fetched from the database implicitly. For non-instance queries the opt.old object is undefined. See the examples.
# Arguments
| Argument | Type | Description |
|---|---|---|
| opt | ModelOptions | Update options. |
| queryContext | Object | The context object of the update query. See context. |
# Return value
| Type | Description |
|---|---|
| Promise (opens new window) void | Promise or void depending whether your hook is async or not. |
# Examples
The current query's transaction/knex instance can always be accessed through queryContext.transaction.
class Person extends Model {
async $afterUpdate(opt, queryContext) {
await super.$afterUpdate(opt, queryContext);
// This can always be done even if there is no running transaction.
// In that case `queryContext.transaction` returns the normal knex
// instance. This makes sure that the query is not executed
// outside the original query's transaction.
await SomeModel.query(queryContext.transaction).insert(whatever);
}
}
Note that the opt.old object is only populated for instance queries started with $query:
somePerson.$query().update(newValues);
For the following query opt.old is undefined because there is no old object in the JavaScript side. objection.js doesn't fetch the old values even if they existed in the database for performance and simplicity reasons.
Person.query()
.update(newValues)
.where('foo', 'bar');
# $beforeDelete()
class Person extends Model {
async $beforeDelete(queryContext) {
await super.$beforeDelete(queryContext);
await doPossiblyAsyncStuff();
}
}
Called before a model is deleted.
You can return a promise from this function if you need to do asynchronous stuff.
WARNING
This method is only called for instance deletes started with $query() method. All hooks are instance methods. For deletes there is no instance for which to call the hook, except when $query() is used. Objection doesn't fetch the item just to call the hook for it to ensure predictable performance and prevent a whole class of concurrency bugs.
# Arguments
| Argument | Type | Description |
|---|---|---|
| queryContext | Object | The context object of the update query. See context. |
# Return value
| Type | Description |
|---|---|
| Promise (opens new window) void | Promise or void depending whether your hook is async or not. |
# Examples
The current query's transaction/knex instance can always be accessed through queryContext.transaction.
class Person extends Model {
async $beforeDelete(queryContext) {
await super.$beforeDelete(queryContext);
// This can always be done even if there is no running transaction.
// In that case `queryContext.transaction` returns the normal knex
// instance. This makes sure that the query is not executed outside
// the original query's transaction.
await SomeModel.query(queryContext.transaction).insert(whatever);
}
}
# $afterDelete()
class Person extends Model {
async $afterDelete(queryContext) {
await super.$afterDelete(queryContext);
await this.doPossiblyAsyncStuff();
}
}
Called after a model is deleted.
You can return a promise from this function if you need to do asynchronous stuff.
WARNING
This method is only called for instance deletes started with $query() method. All hooks are instance methods. For deletes there is no instance for which to call the hook, except when $query() is used. Objection doesn't fetch the item just to call the hook for it to ensure predictable performance and prevent a whole class of concurrency bugs.
# Arguments
| Argument | Type | Description |
|---|---|---|
| queryContext | Object | The context object of the update query. See context. |
# Return value
| Type | Description |
|---|---|
| Promise (opens new window) void | Promise or void depending whether your hook is async or not. |
# Examples
The current query's transaction/knex instance can always be accessed through queryContext.transaction.
class Person extends Model {
async $afterDelete(queryContext) {
await super.$afterDelete(queryContext);
// This can always be done even if there is no running transaction. In that
// case `queryContext.transaction` returns the normal knex instance. This
// makes sure that the query is not executed outside the original query's
// transaction.
await SomeModel.query(queryContext.transaction).insert(whatever);
}
}
# $afterFind()
class Person extends Model {
$afterFind(queryContext) {
return doPossiblyAsyncStuff();
}
}
Called after a model is fetched.
This method is not called for insert, update or delete operations.
You can return a promise from this function if you need to do asynchronous stuff.
# Arguments
| Argument | Type | Description |
|---|---|---|
| queryContext | Object | The context object of the update query. See context. |
# Return value
| Type | Description |
|---|---|
| Promise (opens new window) void | Promise or void depending whether your hook is async or not. |
# Examples
The current query's transaction/knex instance can always be accessed through queryContext.transaction.
class Person extends Model {
$afterFind(queryContext) {
// This can always be done even if there is no running transaction.
// In that case `queryContext.transaction` returns the normal knex
// instance. This makes sure that the query is not executed outside
// the original query's transaction.
return SomeModel.query(queryContext.transaction).insert(whatever);
}
}
# $clone()
const clone = modelInstance.$clone(options);
Returns a (deep) copy of a model instance.
If the item to be cloned has instances of Model as properties (or arrays of them) they are cloned using their $clone() method. A shallow copy without relations can be created by passing the shallow: true option.
# Arguments
| Argument | Type | Description |
|---|---|---|
| opt | CloneOptions | Optional options |
# Return value
| Type | Description |
|---|---|
| Model | Deep clone of this |
# Examples
const shallowClone = modelInstance.$clone({ shallow: true });
# toJSON()
const jsonObj = modelInstance.toJSON(opt);
Exports this model as a JSON object.
See this section for more information.
# Arguments
| Argument | Type | Description |
|---|---|---|
| opt | ToJsonOptions | Optional options |
# Return value
| Type | Description |
|---|---|
| Object | Model as a JSON object. |
# Examples
const shallowObj = modelInstance.toJSON({ shallow: true, virtuals: false });
const onlySomeVirtuals = modelInstance.toJSON({ virtuals: ['fullName'] });
# $toJson()
Alias for toJSON
# $toDatabaseJson()
const row = modelInstance.$toDatabaseJson();
Exports this model as a database JSON object.
This method is called internally to convert a model into a database row.
See this section for more information.
# Return value
| Type | Description |
|---|---|
| Object | Database row. |
# $parseDatabaseJson()
class Person extends Model {
$parseDatabaseJson(json) {
// Remember to call the super class's implementation.
json = super.$parseDatabaseJson(json);
// Do your conversion here.
return json;
}
}
This is called when a Model instance is created from a database JSON object. This method converts the JSON object from the database format to the internal format.
You can override this method to carry out whatever conversions you want for the data when it's fetched from the database, before it's converted into a model instance. See this section for more information.
There are a couple of requirements for the implementation:
This function must be pure. It shouldn't have any side effects because it is called from "unexpected" places (for example to determine if your model somehow transforms column names between db and code).
This function must be able to handle any subset of the model's properties coming in.You cannot assume that some column is present in the
jsonobject as it depends on the select statement. There can also be additional columns because of joins, aliases etc. This method must also be prepared for null values in any property of thejsonobject.
# Arguments
| Argument | Type | Description |
|---|---|---|
| json | Object | The JSON POJO in database format |
# Return value
| Type | Description |
|---|---|
| Object | The JSON POJO in internal format |
# $formatDatabaseJson()
class Person extends Model {
$formatDatabaseJson(json) {
// Remember to call the super class's implementation.
json = super.$formatDatabaseJson(json);
// Do your conversion here.
return json;
}
}
This is called when a Model is converted to database format.
You can override this method to carry out whatever conversions you want for the data when it's being sent to the database driver. See this section for more information.
There are a couple of requirements for the implementation:
This function must be pure. It shouldn't have any side effects because it is called from "unexpected" places (for example to determine if your model somehow transforms column names between db and code).
This function must be able to handle any subset of the model's properties coming in. You cannot assume that some property is present in the
jsonobject. There can also be additional properties. This method must also be prepared for null values in any property of thejsonobject.
# Arguments
| Argument | Type | Description |
|---|---|---|
| json | Object | The JSON POJO in internal format |
# Return value
| Type | Description |
|---|---|
| Object | The JSON POJO in database format |
# $parseJson()
class Person extends Model {
$parseJson(json, opt) {
// Remember to call the super class's implementation.
json = super.$parseJson(json, opt);
// Do your conversion here.
return json;
}
}
This is called when a Model is created from a JSON object. Converts the JSON object from the external format to the internal format.
You can override this method to carry out whatever conversions you want for the data when a model instance is being created from external data. See this section for more information.
There are a couple of requirements for the implementation:
This function must be pure. It shouldn't have any side effects because it is called from "unexpected" places (for example to determine if your model somehow transforms column names between db and code).
This function must be able to handle any subset of the model's properties coming in. You cannot assume that some property is present in the
jsonobject. There can also be additional properties. This method must also be prepared for null values in any property of thejsonobject.
# Arguments
| Argument | Type | Description |
|---|---|---|
| json | Object | The JSON POJO in external format |
| opt | ModelOptions | Optional options |
# Return value
| Type | Description |
|---|---|
| Object | The JSON POJO in internal format |
# $formatJson()
class Person extends Model {
$formatJson(json) {
// Remember to call the super class's implementation.
json = super.$formatJson(json);
// Do your conversion here.
return json;
}
}
This is called when a Model is converted to JSON. Converts the JSON object from the internal format to the external format.
You can override this method to carry out whatever conversions you want for the data when a model instance is being converted into external representation. See this section for more information.
There are a couple of requirements for the implementation:
This function must be pure. It shouldn't have any side effects because it is called from "unexpected" places (for example to determine if your model somehow transforms column names between db and code).
This function must be able to handle any subset of the model's properties coming in. You cannot assume that some column is present in the
jsonobject as it depends on the select statement. There can also be additional columns because of joins, aliases etc. This method must also be prepared for null values in any property of thejsonobject.
# Arguments
| Argument | Type | Description |
|---|---|---|
| json | Object | The JSON POJO in internal format |
# Return value
| Type | Description |
|---|---|
| Object | The JSON POJO in external format |
# $setJson()
modelInstance.$setJson(json, opt);
Sets the values from a JSON object.
Validates the JSON before setting values.
# Arguments
| Argument | Type | Description |
|---|---|---|
| json | Object | The JSON POJO to set |
| opt | ModelOptions | Optional options |
# Return value
| Type | Description |
|---|---|
| Model | this for chaining |
# $setDatabaseJson()
modelInstance.$setDatabaseJson(json);
Sets the values from a JSON object in database format.
# Arguments
| Argument | Type | Description |
|---|---|---|
| json | Object | The JSON POJO in database format |
# Return value
| Type | Description |
|---|---|
| Model | this for chaining |
# $set()
modelInstance.$set(json);
Sets the values from another model instance or object.
Unlike $setJson, this doesn't call any $parseJson hooks or validate the input. This simply sets each value in the object to this object.
# Arguments
| Argument | Type | Description |
|---|---|---|
| obj | Object | The values to set |
# Return value
| Type | Description |
|---|---|
| Model | this for chaining |
# $setRelated()
modelInstance.$setRelated(relation, relatedModels);
Sets related models to a corresponding property in the object.
# Arguments
| Argument | Type | Description |
|---|---|---|
| relation | string|Relation | Relation name or a relation instance to set. |
| relatedModels | Model|Model[] | Models to set. |
# Return value
| Type | Description |
|---|---|
| Model | this for chaining |
# Examples
person.$setRelated('parent', parent);
console.log(person.parent);
person.$setRelated('children', children);
console.log(person.children[0]);
# $appendRelated()
modelInstance.$appendRelated(relation, relatedModels);
Appends related models to a corresponding property in the object.
# Arguments
| Argument | Type | Description |
|---|---|---|
| relation | string|Relation | Relation name or a relation instance to append to. |
| relatedModels | Model|Model[] | Models to append. |
# Return value
| Type | Description |
|---|---|
| Model | this for chaining |
# Examples
person.$appendRelated('parent', parent);
console.log(person.parent);
person.$appendRelated('children', child1);
person.$appendRelated('children', child2);
child1 = person.children[person.children.length - 1];
child2 = person.children[person.children.length - 2];
# $fetchGraph()
const builder = person.$fetchGraph(expression, options);
Shortcut for Person.fetchGraph(person, options)
# $traverse()
person.$traverse(filterConstructor, callback);
Shortcut for Model.traverse(filterConstructor, this, callback).
# $traverseAsync()
person.$traverseAsync(filterConstructor, callback);
Shortcut for Model.traverseAsync(filterConstructor, this, callback).
# $knex()
const knex = person.$knex();
Shortcut for Person.knex().
# $transaction()
const knex = person.$transaction();
Shortcut for Person.knex().
# $id()
console.log(model.$id()); // -> 100
// Sets the id.
model.$id(100);
Returns or sets the identifier of a model instance.
The identifier property does not have to be accessed or set using this method.
If the identifier property is known it can be accessed or set just like any other property. You don't need to use this method to set the identifier. This method is mainly helpful when building plugins and other tools on top of objection.
# Examples
Composite key
console.log(model.$id()); // -> [100, 20, 30]
// Sets the id.
model.$id([100, 20, 30]);
# $beforeValidate()
class Person extends Model {
$beforeValidate(jsonSchema, json, opt) {
return jsonSchema;
}
}
This is called before validation.
You can add any additional validation to this method. If validation fails, simply throw an exception and the query will be rejected. If you modify the jsonSchema argument and return it, that one will be used to validate the model.
opt.old object contains the old values while json contains the new values if validation is being done for an existing object.
# Arguments
| Argument | Type | Description |
|---|---|---|
| jsonSchema | Object | A deep clone of this class's jsonSchema |
| json | Object | The JSON object to be validated |
| opt | ModelOptions | Optional options |
# Return value
| Type | Description |
|---|---|
| Object | The modified jsonSchema or the input jsonSchema. |
# $afterValidate()
class Person extends Model {
$afterValidate(json, opt) {}
}
This is called after successful validation.
You can do further validation here and throw an error if something goes wrong.
opt.old object contains the old values while json contains the new values if validation is being done for an existing object.
# Arguments
| Argument | Type | Description |
|---|---|---|
| json | Object | The JSON object to be validated |
| opt | ModelOptions | Optional options |
# $validate()
modelInstance.$validate();
Validates the model instance.
Calls $beforeValidate and $afterValidate methods. This method is called automatically from fromJson and $setJson methods. This method can also be called explicitly when needed.
# Throws
| Type | Description |
|---|---|
| ValidationError | If validation fails. |
# $omitFromJson()
modelInstance.$omitFromJson(props);
Omits a set of properties when converting the model to JSON.
# Arguments
| Argument | Type | Description |
|---|---|---|
| props | string string[] Object<string, boolean> | props to omit |
# Return value
| Type | Description |
|---|---|
| Model | this for chaining |
# Examples
const json = person
.fromJson({ firstName: 'Jennifer', lastName: 'Lawrence', age: 24 })
.$omitFromJson('lastName')
.$toJson();
console.log(_.has(json, 'lastName')); // --> false
const json = person
.fromJson({ firstName: 'Jennifer', lastName: 'Lawrence', age: 24 })
.$omitFromJson(['lastName'])
.$toJson();
console.log(_.has(json, 'lastName')); // --> false
const json = person
.fromJson({ firstName: 'Jennifer', lastName: 'Lawrence', age: 24 })
.$omitFromJson({ lastName: true })
.$toJson();
console.log(_.has(json, 'lastName')); // --> false
# $omitFromDatabaseJson()
modelInstance.$omitFromDatabaseJson(props);
Omits a set of properties when converting the model to database JSON.
# Arguments
| Argument | Type | Description |
|---|---|---|
| props | string string[] Object<string, boolean> | props to omit |
# Return value
| Type | Description |
|---|---|
| Model | this for chaining |
# Examples
const json = person
.fromJson({ firstName: 'Jennifer', lastName: 'Lawrence', age: 24 })
.$omitFromDatabaseJson('lastName')
.$toDatabaseJson();
console.log(_.has(json, 'lastName')); // --> false
const json = person
.fromJson({ firstName: 'Jennifer', lastName: 'Lawrence', age: 24 })
.$omitFromJson(['lastName'])
.$toDatabaseJson();
console.log(_.has(json, 'lastName')); // --> false
const json = person
.fromJson({ firstName: 'Jennifer', lastName: 'Lawrence', age: 24 })
.$omitFromJson({ lastName: true })
.$toDatabaseJson();
console.log(_.has(json, 'lastName')); // --> false