# Other Methods
# debug()
Chaining this method to any query will print all the executed SQL to console.
Seeknex documentation(opens new window)
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# toKnexQuery()
knexQueryBuilder= queryBuilder.toKnexQuery();Compiles the query into a knex query and returns the knex query builder instance.
Some objection queries, like whenwithGraphFetched is used, actually execute multiple queries. In these cases, the query builer of the first query is returned
In some rare cases the knex query cannot be built synchronously. In these cases you will get a clear error message. These cases can be handled by calling the optionalinitialize method once before the failingtoKnexQuery method is called.
const{ initialize}=require('objection');awaitinitialize([Person, Pet, Movie, SomeOtherModelClass]);# for()
queryBuilder= queryBuilder.for(relationOwner);This method can only be used in conjunction with the staticrelatedQuery method. See therelatedQuery documentation on how to use it.
This method takes one argument (the owner(s) of the relation) and it can have any of the following types:
- A single identifier (can be composite)
- An array of identifiers (can be composite)
- AQueryBuilder
- A model instance.
- An array of model instances.
# context()
queryBuilder= queryBuilder.context(queryContext);Sets/gets the query context.
Some query builder methods create more than one query. The query context is an object that is shared with all queries started by a query builder.
The context is also passed to$beforeInsert,$afterInsert,$beforeUpdate,$afterUpdate,$beforeDelete,$afterDelete and$afterFind calls that the query creates.
In addition to properties added using this method the query context object always has atransaction property that holds the active transaction. If there is no active transaction thetransaction property contains the normal knex instance. In both cases the value can be passed anywhere where a transaction object can be passed so you never need to check for the existence of thetransaction property.
This method merges the given object with the current context. You can useclearContext to clear the context if needed.
See the methodsrunBefore,onBuild andrunAfterfor more information about the hooks.
# Arguments
| Argument | Type | Description |
|---|---|---|
| queryContext | Object | The query context object |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# Examples
You can set the context like this:
await Person.query().context({something:'hello'});and access the context like this:
const context= builder.context();You can set any data to the context object. You can also register QueryBuilder lifecycle methods forall queries that share the context:
Person.query().context({runBefore(result, builder){return result;},runAfter(result, builder){return result;},onBuild(builder){}});For example thewithGraphFetched method causes multiple queries to be executed from a single query builder. If you wanted to make all of them use the same schema you could write this:
Person.query().withGraphFetched('[movies, children.movies]').context({onBuild(builder){ builder.withSchema('someSchema');}});# clearContext()
queryBuilder= queryBuilder.clearContext();Replaces the current context with an empty object.
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# tableNameFor()
const tableName= queryBuilder.tableNameFor(modelClass);Returns the table name for a given model class in the query. Usually the table name can be fetched throughModel.tableName but if the source table has been changed for example using theQueryBuilder#table methodtableNameFor will return the correct value.
# Arguments
| Argument | Type | Description |
|---|---|---|
| modelClass | function | A model class. |
# Return value
| Type | Description |
|---|---|
| string | The source table (or view) name formodelClass. |
# tableRefFor()
const tableRef= queryBuilder.tableRefFor(modelClass);Returns the name that should be used to refer to themodelClass's table in the query.Usually a table can be referred to using its name, buttableRefFor can return a differentvalue for example in case an alias has been given.
# Arguments
| Argument | Type | Description |
|---|---|---|
| modelClass | function | A model class. |
# Return value
| Type | Description |
|---|---|
| string | The name that should be used to refer to a table in the query. |
# reject()
queryBuilder= queryBuilder.reject(reason);Skips the database query and "fakes" an error result.
# Arguments
| Argument | Type | Description |
|---|---|---|
| reason | The rejection reason |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# resolve()
queryBuilder= queryBuilder.resolve(value);Skips the database query and "fakes" a result.
# Arguments
| Argument | Type | Description |
|---|---|---|
| value | The resolve value |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# isExecutable()
const isExecutable= queryBuilder.isExecutable();Returns false if this query will never be executed.
This may be true in multiple cases:
- The query is explicitly resolved or rejected using theresolve orreject methods.
- The query starts a different query when it is executed.
# Return value
| Type | Description |
|---|---|
| boolean | false if the query will never be executed. |
# isFind()
const isFind= queryBuilder.isFind();Returns true if the query is read-only.
# Return value
| Type | Description |
|---|---|
| boolean | true if the query is read-only. |
# isInsert()
const isInsert= queryBuilder.isInsert();Returns true if the query performs an insert operation.
# Return value
| Type | Description |
|---|---|
| boolean | true if the query performs an insert operation. |
# isUpdate()
const isUpdate= queryBuilder.isUpdate();Returns true if the query performs an update or patch operation.
# Return value
| Type | Description |
|---|---|
| boolean | true if the query performs an update or patch operation. |
# isDelete()
const isDelete= queryBuilder.isDelete();Returns true if the query performs a delete operation.
# Return value
| Type | Description |
|---|---|
| boolean | true if the query performs a delete operation. |
# isRelate()
const isRelate= queryBuilder.isRelate();Returns true if the query performs a relate operation.
# Return value
| Type | Description |
|---|---|
| boolean | true if the query performs a relate operation. |
# isUnrelate()
const isUnrelate= queryBuilder.isUnrelate();Returns true if the query performs an unrelate operation.
# Return value
| Type | Description |
|---|---|
| boolean | true if the query performs an unrelate operation. |
# isInternal()
const isInternal= queryBuilder.isInternal();Returns true for internal "helper" queries that are not directlypart of the operation being executed. For example theselect queriesperformed byupsertGraph to get the current state of the graph areinternal queries.
# Return value
| Type | Description |
|---|---|
| boolean | true if the query performs an internal helper operation. |
# hasWheres()
const hasWheres= queryBuilder.hasWheres();Returns true if the query contains where statements.
# Return value
| Type | Description |
|---|---|
| boolean | true if the query contains where statements. |
# hasSelects()
const hasSelects= queryBuilder.hasSelects();Returns true if the query contains any specific select staments, such as:'select','columns','column','distinct','count','countDistinct','min','max','sum','sumDistinct','avg','avgDistinct'
# Return value
| Type | Description |
|---|---|
| boolean | true if the query contains any specific select staments. |
# hasWithGraph()
const hasWithGraph= queryBuilder.hasWithGraph();Returns true ifwithGraphFetched orwithGraphJoined has been called for the query.
# Return value
| Type | Description |
|---|---|
| boolean | true ifwithGraphFetched orwithGraphJoined has been called for the query. |
# has()
const has= queryBuilder.has(selector);console.log( Person.query().range(0,4).has('range'));Returns true if the query defines an operation that matches the given selector.
# Arguments
| Argument | Type | Description |
|---|---|---|
| selector | string | RegExp | A name or regular expression to match all defined operations against. |
# Return value
| Type | Description |
|---|---|
| boolean | true if the query defines an operation that matches the given selector. |
# clear()
queryBuilder= queryBuilder.clear(selector);Removes all operations in the query that match the given selector.
# Arguments
| Argument | Type | Description |
|---|---|---|
| selector | string | regexp | A name or regular expression to match all operations that are to be removed against. |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# Examples
console.log( Person.query().orderBy('firstName').clear('orderBy').has('orderBy'));# runBefore()
queryBuilder= queryBuilder.runBefore(runBefore);Registers a function to be called before just the database query when the builder is executed. Multiple functions can be chained likethen methods of a promise.
# Arguments
| Argument | Type | Description |
|---|---|---|
| runBefore | function(result, QueryBuilder) | The function to be executed. This function can be async. Note that it needs to return the result used for further processing in the chain of calls. |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# Examples
const query= Person.query();query.runBefore(asyncresult=>{ console.log('hello 1');await Promise.delay(10); console.log('hello 2');return result;}).runBefore(result=>{ console.log('hello 3');return result;});await query;// --> hello 1// --> hello 2// --> hello 3# onBuild()
queryBuilder= queryBuilder.onBuild(onBuild);Functions registered with this method are called each time the query is built into an SQL string. This method is ran afterrunBefore methods but beforerunAfter methods.
If you need to modify the SQL query at query build time, this is the place to do it. You shouldn't modify the query in any of therun methods.
Unlike therun methods (runAfter,runBefore etc.) these must be synchronous. Also you should not register anyrun methods from these. You shouldonly call the query building methods of the builder provided as a parameter.
# Arguments
| Argument | Type | Description |
|---|---|---|
| onBuild | function(QueryBuilder) | Thesynchronous function to be executed. |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# Eamples
const query= Person.query();query.onBuild(builder=>{ builder.where('id',1);}).onBuild(builder=>{ builder.orWhere('id',2);});# onBuildKnex()
queryBuilder= queryBuilder.onBuildKnex(onBuildKnex);Functions registered with this method are called each time the query is built into an SQL string. This method is ran afteronBuild methods but beforerunAfter methods.
If you need to modify the SQL query at query build time, this is the place to do it in addition toonBuild. The only difference betweenonBuildKnex andonBuild is that inonBuild you can modify the objection's query builder. InonBuildKnex the objection builder has been compiled into a knex query builder and any modifications to the objection builder will be ignored.
Unlike therun methods (runAfter,runBefore etc.) these must be synchronous. Also you should not register anyrun methods from these. You shouldonly call the query building methods of theknexBuilder provided as a parameter.
WARNING
You should never call any query building (or any other mutating) method on theobjectionBuilder in this function. If you do, those calls will get ignored. At this point the query builder has been compiled into a knex query builder and you should only modify that. You can call non mutating methods likehasSelects,hasWheres etc. on the objection builder.
# Arguments
| Argument | Type | Description |
|---|---|---|
| onBuildKnex | function(KnexQueryBuilder, QueryBuilder) | The function to be executed. |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# Examples
const query= Person.query();query.onBuildKnex((knexBuilder, objectionBuilder)=>{ knexBuilder.where('id',1);});# runAfter()
queryBuilder= queryBuilder.runAfter(runAfter);Registers a function to be called when the builder is executed.
These functions are executed as the last thing before any promise handlers registered using thethen method. Multiple functions can be chained likethen methods of a promise.
# Arguments
| Argument | Type | Description |
|---|---|---|
| runAfter | function(result, QueryBuilder) | The function to be executed. This function can be async. Note that it needs to return the result used for further processing in the chain of calls. |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# Examples
const query= Person.query();query.runAfter(async(models, queryBuilder)=>{return models;}).runAfter(async(models, queryBuilder)=>{ models.push(Person.fromJson({firstName:'Jennifer'}));return models;});const models=await query;# onError()
queryBuilder= queryBuilder.onError(onError);Registers an error handler. Just likecatch but doesn't execute the query.
# Arguments
| Argument | Type | Description |
|---|---|---|
| onError | function(Error, QueryBuilder) | The function to be executed on error. |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# Examples
const query= Person.query();query.onError(async(error, queryBuilder)=>{// Handle `SomeError` but let other errors go through.if(errorinstanceofSomeError){// This will cause the query to be resolved with an object// instead of throwing an error.return{error:'some error occurred'};}else{return Promise.reject(error);}}).where('age','>',30);# castTo()
queryBuilder= queryBuilder.castTo(ModelClass);queryBuilder= queryBuilder.castTo<SomeType>();Sets the model class of the result rows or if no arguments are provided, simply casts theresult type to the provided type.
# Return value
| Type | Description |
|---|---|
| ModelClass | The model class of the result rows. |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# Examples
The following example creates a query throughPerson, joins a bunch of relations, selectsonly the relatedAnimal's columns and returns the results asAnimal instances insteadofPerson instances.
const animals=await Person.query().joinRelated('children.children.pets').select('children:children:pets.*').castTo(Animal);If you don't provide any arguments for the method, but provide a generic type argument, theresult is not changed but its typescript type is cast to the given generic type.
interfaceNamed{ name:string;}const result=await Person.query().select('firstName as name').castTo<Named[]>();console.log(result[0].name);# modelClass()
const modelClass= queryBuilder.modelClass();Gets the Model subclass this builder is bound to.
# Return value
| Type | Description |
|---|---|
| Model | The Model subclass this builder is bound to |
# skipUndefined()
queryBuilder= queryBuilder.skipUndefined();If this method is called for a builder then undefined values passed to the query builder methods don't cause an exception but are ignored instead.
For example the following query will return allPerson rows ifreq.query.firstName isundefined.
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining |
# Examples
Person.query().skipUndefined().where('firstName', req.query.firstName);# transacting()
queryBuilder= queryBuilder.transacting(transaction);Sets the transaction for a query.
# Arguments
| Argument | Type | Description |
|---|---|---|
| transaction | object | A transaction object |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining |
# clone()
const clone= queryBuilder.clone();Create a clone of this builder.
| Type | Description |
|---|---|
| QueryBuilder | Clone of the query builder |
# execute()
const promise= queryBuilder.execute();Executes the query and returns a Promise.
# Return value
| Type | Description |
|---|---|
Promise | Promise the will be resolved with the result of the query. |
# then()
const promise= queryBuilder.then(successHandler, errorHandler);Executes the query and returns a Promise.
# Arguments
| Argument | Type | Default | Description |
|---|---|---|---|
| successHandler | function | identity | Promise success handler |
| errorHandler | function | identity | Promise error handler |
# Return value
| Type | Description |
|---|---|
Promise | Promise the will be resolved with the result of the query. |
# catch()
const promise= queryBuilder.catch(errorHandler);Executes the query and callscatch(errorHandler) for the returned promise.
# Arguments
| Argument | Type | Default | Description |
|---|---|---|---|
| errorHandler | function | identity | Error handler |
# Return value
| Type | Description |
|---|---|
Promise | Promise the will be resolved with the result of the query. |
# bind()
const promise=queryBuilder.bind(returnValue);Executes the query and callsbind(context) for the returned promise.
# Arguments
| Argument | Type | Default | Description |
|---|---|---|---|
| context | undefined | Bind context |
# Return value
| Type | Description |
|---|---|
Promise | Promise the will be resolved with the result of the query. |
# resultSize()
const promise= queryBuilder.resultSize();Returns the amount of rows the current query would produce withoutlimit andoffset applied. Note that this executes a copy of the query and returns a Promise.
This method is often more convenient thancount which returns an array of objects instead a single number.
# Return value
| Type | Description |
|---|---|
Promise<number> | Promise the will be resolved with the result size. |
# Examples
const query= Person.query().where('age','>',20);const[total, models]=await Promise.all([ query.resultSize(), query.offset(100).limit(50)]);# page()
queryBuilder= queryBuilder.page(page, pageSize);const result=await Person.query().where('age','>',20).page(5,100);console.log(result.results.length);// --> 100console.log(result.total);// --> 3341Two queries are performed by this method: the actual query and a query to get thetotal count.
Mysql has theSQL_CALC_FOUND_ROWS option andFOUND_ROWS() function that can be used to calculate the result size, but according to my tests andthe interwebs(opens new window) the performance is significantly worse than just executing a separate count query.
Postgresql has window functions that can be used to get the total count like thisselect count(*) over () as total. The problem with this is that if the result set is empty, we don't get the total count either. (If someone can figure out a way around this, a PR is very welcome).
# Arguments
| Argument | Type | Description |
|---|---|---|
| page | number | The index of the page to return. The index of the first page is 0. |
| pageSize | number | The page size |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining |
# range()
queryBuilder= queryBuilder.range(start, end);Only returns the given range of results.
Two queries are performed by this method: the actual query and a query to get thetotal count.
Mysql has theSQL_CALC_FOUND_ROWS option andFOUND_ROWS() function that can be used to calculate the result size, but according to my tests andthe interwebs(opens new window) the performance is significantly worse than just executing a separate count query.
Postgresql has window functions that can be used to get the total count like thisselect count(*) over () as total. The problem with this is that if the result set is empty, we don't get the total count either. (If someone can figure out a way around this, a PR is very welcome).
# Arguments
| Argument | Type | Description |
|---|---|---|
| start | number | The index of the first result (inclusive) |
| end | number | The index of the last result (inclusive) |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining |
# Examples
const result=await Person.query().where('age','>',20).range(0,100);console.log(result.results.length);// --> 101console.log(result.total);// --> 3341range can be called without arguments if you want to specify the limit and offset explicitly:
const result=await Person.query().where('age','>',20).limit(10).range();console.log(result.results.length);// --> 101console.log(result.total);// --> 3341# first()
queryBuilder= queryBuilder.first();If the result is an array, selects the first item.
NOTE: This doesn't addlimit 1 to the query by default. You can override theModel.useLimitInFirst property to change this behaviour.
Also seefindById andfindOne shorthand methods.
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining |
# Examples
const firstPerson=await Person.query().first();console.log(firstPerson.age);# throwIfNotFound()
queryBuilder= queryBuilder.throwIfNotFound(data);Causes aModel.NotFoundError to be thrown if the query result is empty.
You can replaceModel.NotFoundError with your own error by implementing the staticModel.createNotFoundError(ctx) method.
# Arguments
| Argument | Type | Description |
|---|---|---|
| data | object | optional object with custom data may contain any property such as message, type. The object is returned in the error thrown under thedata property. A special case is for the optional message property. This is used to set the title of the error. These extra properties can be leveraged in the error handling middleware |
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining |
# Examples
try{await Language.query().where('name','Java').andWhere('isModern',true).throwIfNotFound({message:`Custom message returned`,type:`Custom type`});}catch(err){// No results found. console.log(errinstanceofLanguage.NotFoundError);// --> true}# timeout()
Seeknex documentation(opens new window)
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# connection()
Seeknex documentation(opens new window)
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# modify()
Works likeknex'smodify(opens new window) function but in addition you can specify amodifier by providing modifier names.
See themodifier recipe for examples of the things you can do with modifiers.
# Arguments
| Argument | Type | Description |
|---|---|---|
| modifier | function(QueryBuilder) | string | string[] | The modify callback function, receiving the builder as its first argument, followed by the optional arguments. If a string or an array of strings is provided, the correspondingmodifier is executed instead. |
| *arguments | ...any | The optional arguments passed to the modify function |
# Examples
The first argument can be a name of amodel modifier. The rest of the arguments are passed as arguments for the modifier.
Person.query().modify('someModifier','foo',1);You can also pass an array of modifier names:
Person.query().modify(['someModifier','someOtherModifier'],'foo',1);The first argument can be a function:
functionmodifierFunc(query, arg1, arg2){ query.where(arg1, arg2);}Person.query().modify(modifierFunc,'foo',1);# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# modifiers()
Registers modifiers for the query.
You can call this method without arguments to get the currently registered modifiers.
See themodifier recipe for more info and examples.
# Return value
| Type | Description |
|---|---|
| QueryBuilder | this query builder for chaining. |
# Examples
const people=await Person.query().modifiers({selectFields:query=> query.select('id','name'),// In the following modifier, `filterGender` is a modifier// registered in Person.modifiers object. Query modifiers// can be used to bind arguments to model modifiers like this.filterWomen:query=> query.modify('filterGender','female')}).modify('selectFields').withGraphFetched('children(selectFields, filterWomen)');You can get the currently registered modifiers by calling the method without arguments.
const modifiers= query.modifiers();