# Retrieving
Vuex ORM provides a handful of methods to retrieve inserted data. In this section, we'll walk through various ways to query the Vuex Store.
When querying the data from the store, in most of the cases you want to query data inside computed
property. This way, when any data changes, the part of your application where you use those data gets updated reactively. It works as same as Vuex Getters, and in fact, Vuex ORM is retrieving data from the store via Vuex Getters.
<template>
<ul>
<li :key="user.id" v-for="user in users">
{{ user.name }}
</li>
</ul>
</template>
<script>
import User from '@/models/User'
export default {
computed: {
users () {
return User.all()
}
}
}
</script>
NOTE: To retrieve records with its relationships, you must explicitly specify which relationships to fetch by
with
query chain. For example, if you want to fetch Users with Posts, you must doUser.query().with('posts').get()
. See Relationships section for more detail.
# Get All Data
The all
method is going to fetch all data from the store.
// get all users.
const users = User.all()
/*
[
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
]
*/
# Get Single Data
The find
method is going to fetch single data from the store. The argument is the id—primary key value—for the record.
// Get a user with id of 1.
const users = User.find(1)
// { id: 1, name: 'John' }
If your model has a composite primary key, you can retrieve data by passing an array as the argument. Let's say you have a Subscription model defined like this.
import { Model } from '@vuex-orm/core'
class Subscription extends Model {
static entity = 'subscription'
static primaryKey = ['video_id', 'user_id']
static fields () {
return {
video_id: this.attr(null),
user_id: this.attr(null)
}
}
}
Then, you can retrieve Subscription records as below. Remember that the value order in the array is the same as the order you defined in your Model's primary key property. In this case it's ['video_id', 'user_id']
.
// Get a subscription with video_id 1 and user_id 2.
const subscription = Subscription.find([1, 2])
// { video_id: 1, user_id: 2 }
# Get Multiple Data by Primary Keys
The findIn
method is going to fetch array of data from the store. The argument is array of ids—primary key value—for the records.
// Retrieve array of records by their primary keys.
const users = User.findIn([1, 2])
/*
[
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
]
*/
Similarly to find
, if your model has a composite primary key you can pass an array of arrays as the argument.
// Retrieve array of records by their composite primary keys.
const subscriptions = Subscription.findIn([[1, 1], [1, 2]])
/*
[
{ video_id: 1, user_id: 1 },
{ video_id: 1, user_id: 2 }
]
*/
# Query Builder
The query
method will return the Query Builder that provides fluent API to search and fetch data from the store. You can use the Query Builder to construct more complex query conditions.
You can obtain Query Builder by calling the query
method.
// Get Query Builder instance.
const query = User.query()
To execute the query, you can either use a get
method. The get
method will execute all query conditions, and get all records that matched to the condition.
// Get all users through Query Builder.
const users = User.query().get()
/*
[
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
]
*/
You may use first
method to fetch a single data for the entity. It will return the very first item of the query results.
// Get the first user of the query.
const user = User.query().first()
// { id: 1, name: 'John' }
As oppose to first
method, the last
method returns the last matching data.
const user = User.query().last()
// { id: 2, name: 'Jane' }
# Where Clauses
Where clause is the most generic way of filtering the records. The first argument should be the name of the field, and the second should be the value.
// Get users with age of 20.
const user = User.query().where('age', 20).get()
You may pass a closure to the 2nd argument when you need more powerful constraints. The argument is the value of the field.
// Get users with age higher than 20.
const user = User.query().where('age', (value) => value > 20).get()
Or, you may pass a closure to the 1st argument to get full control of the condition. The argument is the data itself.
// Get users with age higher than 20 and also a female.
const user = User.query().where((user) => {
return user.age > 20 && user.sex === 'female'
}).get()
NOTE: When returning the result of the condition, you must explicitly return a boolean,
true
orfalse
. It will not work if you return a falsy value other thanfalse
, for example,undefined
ornull
. See GitHub Issue #402 for more details.
When passing a closure to the 1st argument, it will also receive Query Builder as the 2nd argument. By using the Query Builder, you may nest the where clause. This is useful when you want "group" the where clauses.
// Retrieve all users with role of user, and age of 20 or id of 1.
const user = User.query()
.where('role', 'user')
.where((_record, query) => {
query.where('age', 20).orWhere('id', 1)
})
.get()
# Get Data By Id
Use whereId
method to fetch a single data by using its id. This filters data faster than other where
methods because it will use direct key lookup. The argument is the id—primary key value—for the record.
const user = User.query().whereId(1).first()
You may also use whereIdIn
method to get multiple records by id look up. The argument is array of ids—primary key values—for the records.
const user = User.query().whereIdIn([1, 2]).get()
# Composite Primary Keys
Both whereId
and whereIdIn
support models with composite primary keys.
const user = User.query().whereId([1, 2]).first()
const users = User.query().whereIdIn([[1, 2], [3, 2]]).get()
# Or Statement
You may chain where constraints together as well as add or
conditions to the query. The orWhere
method accepts the same arguments as the where
method.
// Fetch users with role of `admin`, or name of `John`.
const user = User.query()
.where('role', 'admin')
.orWhere('name', 'John')
.get()
# Exists
The exists
method allows you to check whether a query chain would return any records. The method will return either true
or false
.
// Check whether the user store contains any data.
const resultExists = User.exists()
// Check whether an user with id 5 exists.
const resultExists = User.query().where('id', 5).exists()
# Order By
The orderBy
method allows you to sort the result of the query by a given field. The first argument to the orderBy method should be the column you wish to sort by, while the second argument controls the direction of the sort, and may be either asc
or desc
. If there is no 2nd argument, the direction is going to be asc
.
// Order users by name.
const users = User.query().orderBy('name').get()
/*
[
{ id: 2, name: 'Andy' },
{ id: 1, name: 'John' }
]
*/
// You may also chain orderBy.
const users = User.query()
.orderBy('name')
.orderBy('age', 'desc')
.get()
/*
[
{ id: 4, name: 'Andy', age: 32 },
{ id: 2, name: 'Andy', age: 27 },
{ id: 6, name: 'Jane', age: 42 }
]
*/
You may also pass a function as the 1st argument. The function will accept a record that is being sorted, and it should return value to be sorted by.
// Sort user name by its 3rd character.
const users = User.query().orderBy(user => user.name[2]).get()
/*
[
{ id: 4, name: 'Andy' },
{ id: 2, name: 'Roger' },
{ id: 1, name: 'John' }
]
*/
# Limit & Offset
Use limit
method to set the maximum number of records to retrieve.
const user = User.query().limit(2).get()
// [{ id: 1, age: 25 }, { id: 2, age: 30 }]
Use offset
method to set the offset for the data.
const user = User.query().offset(2).get()
// [{ id: 3, age: 35 }, { id: 4, age: 40 }]
Both offset
and limit
can be chained together to paginate through data.
const user = User.query().offset(1).limit(2).get()
// [{ id: 2, age: 30 }, { id: 3, age: 35 }]
# Aggregates
The Query Builder also provides aggregate methods. Available methods are count
, max
, min
and sum
.
const users = User.query().count()
const mostLiked = Post.query().max('like')
const cheapest = Order.query().min('price')
const total = Order.query().sum('price')
Of course, you may combine these methods with other clauses.
const users = User.query().where('role', 'user').count()
# Relationships
You can use the with
method to load related model when querying data. The argument to the with
method should be the name of the field that defines the relationship, not the entity name of the related model.
const user = User.query().with('profile').with('posts').first()
/*
{
id: 1,
name: 'John',
profile: {
id: 1,
user_id: 1,
age: 24
},
posts: [
{ id: 1, user_id: 1, body: '...' },
{ id: 2, user_id: 1, body: '...' }
]
}
*/
# Load Nested Relation
You can load nested relations with dot syntax.
const user = User.query().with('posts.comments').first()
/*
{
id: 1,
name: 'john',
posts: [
{
id: 1,
user_id: 1,
body: '...',
comments: [
{ id: 1, post_id: 1, body: '...' },
{ id: 2, post_id: 1, body: '...' }
]
},
{
id: 2,
user_id: 1,
body: '...',
comments: [
{ id: 3, post_id: 2, body: '...' },
{ id: 4, post_id: 2, body: '...' }
]
}
]
}
*/
You can load multiple sub relations by separating them with |
(symbolizing the or
syntax):
// Fetching all comments & reviews from user.posts.
const user = User.query()
.with('posts.comments|reviews')
.first()
Or passing an array of relations (in that case, the full path is needed):
// Fetching all comments & reviews from user.posts + user.profile.
const user = User.query()
.with(['posts.comments', 'posts.reviews', 'profile'])
.first()
# Load All Relations
You can load all relations on a model using the withAll
method.
const user = User.query().withAll().first()
/*
{
id: 1,
name: 'john',
profile: {
id: 1,
user_id: 1,
age: 24
},
posts: [
{
id: 1,
user_id: 1,
body: '...'
},
{
id: 2,
user_id: 1,
body: '...'
}
]
}
*/
Constraints may also be added for more granular control.
const user = User.query().withAll((query) => {
query.has('comments')
}).first()
To fetch all sub relations of a relation using the dot syntax, use *
.
// Fetches all relations of all posts.
const user = User.query().with('posts.*').first()
To fetch all sub relations to a certain level you can use the withAllRecursive
method. You can specify a depth to which relations should be loaded. The depth defaults to 3, so if you call withAllRecursive
with no arguments, it will fetch all sub relations of sub relations of sub relations of the queried entity.
const user = User.query().withAllRecursive().first()
/*
User {
id: 1,
name: 'john',
profile: {
id: 1,
user_id: 1,
age: 24
},
posts: [
{
id: 1,
user_id: 1,
body: '...',
comments: [
{ id: 1, post_id: 1, body: '...' },
{ id: 2, post_id: 1, body: '...' }
]
},
{
id: 2,
user_id: 1,
body: '...',
comments: [
{ id: 3, post_id: 2, body: '...' },
{ id: 4, post_id: 2, body: '...' }
]
},
]
}
*/
# Relationship Constraints
To filter the result of relation loaded by the with
method, you can pass a closure to the second argument to define additional constraints to the query.
// Get all users with posts that have `published` field value of `true`.
const user = User.query().with('posts', (query) => {
query.where('published', true)
}).get()
/*
[
{
id: 1,
name: 'John',
posts: [
{ id: 1, user_id: 1, body: '...', published: true },
{ id: 2, user_id: 1, body: '...', published: true }
]
}
]
*/
When you add constraints to the "nested" relation, the constraints will be applied to the deepest relationship.
const user = User.query().with('posts.comments', (query) => {
// This constraint will be applied to the `comments`, not `posts`.
query.where('type', 'review')
}).get()
Similarly, you may add constraints to wildcard relations. For example, posts
may have comments
and tags
, all of which will be ordered by the created_at
field.
const user = User.query().with('posts.*', (query) => {
// This constraint will be applied to all relations belonging to `posts`
query.orderBy('created_at', 'desc')
}).get()
If you need to add constraints to each relation, you could always nest constraints. This is the most flexible way of defining constraints to the relationships.
const user = User.query().with('posts', (query) => {
query.with('comments', (query) => {
query.where('type', 'review')
}).where('published', true)
}).get()
# Relationship Existence & Absence
When querying the record, you may wish to limit your results based on the existence of a relationship. For example, imagine you want to retrieve all blog posts that have at least one comment. To do so, you may pass the name of the relationship to the has
methods.
// Retrieve all posts that have at least one comment.
Post.query().has('comments').get()
You may also specify count as well.
// Retrieve all posts that have at least 2 comments.
Post.query().has('comments', 2).get()
Also, you may add an operator to customize your query even more. The supported operators are =
, >
, >=
, <
and <=
.
// Retrieve all posts that have more than 2 comments.
Post.query().has('comments', '>', 2).get()
// Retrieve all posts that have less than or exactly 2 comments.
Post.query().has('comments', '<=', 2).get()
If you need even more power, you may use the whereHas
method to put "where" conditions on your has
queries. This method allows you to add customized constraints to a relationship constraint, such as checking the content of a comment.
// Retrieve all posts that have comment from user_id 1.
Post.query().whereHas('comments', (query) => {
query.where('user_id', 1)
}).get()
To retrieve records depending on the absence of the relationship, use the hasNot
and whereHasNot
methods. These methods will work the same as has
and whereHas
but with the opposite result.
// Retrieve all posts that doesn't have comments.
Post.query().hasNot('comments').get()
// Retrieve all posts that doesn't have comment with user_id of 1.
Post.query().whereHasNot('comments', (query) => {
query.where('user_id', 1)
}).get()