mirror of https://github.com/vapor/docs.git
195 lines
8.1 KiB
Markdown
195 lines
8.1 KiB
Markdown
# Fluent Queries
|
|
|
|
Once you have a [model](models.md) you can start querying your database to create, read, update, and delete data.
|
|
|
|
## Connection
|
|
|
|
The first thing you need to query your database, is a connection to it. Luckily, they are easy to get.
|
|
|
|
### Request
|
|
|
|
The easiest way to connect to your database is simply using the incoming `Request`. This will use the model's [`defaultDatabase`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE15defaultDatabase0D3Kit0D10IdentifierVy0D0QzGSgvpZ) property to automatically fetch a pooled connection to the database.
|
|
|
|
```swift
|
|
router.get("galaxies") { req in
|
|
return Galaxy.query(on: req).all()
|
|
}
|
|
```
|
|
|
|
You can use convenience methods on a `Container` to create connections manually. Learn more about that in [DatabaseKit → Overview → Connections](../database-kit/overview/#connections).
|
|
|
|
## Create
|
|
|
|
One of the first things you will need to do is save some data to your database. You do this by initializing an instance of your model then calling [`create(on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE6create2on3NIO15EventLoopFutureCyxG11DatabaseKit0I11Connectable_p_tF).
|
|
|
|
```swift
|
|
router.post("galaxies") { req in
|
|
let galaxy: Galaxy = ...
|
|
return galaxy.create(on: req)
|
|
}
|
|
```
|
|
|
|
The create method will return the saved model. The returned model will include any generated fields such as the ID or fields with default values.
|
|
|
|
If your model also conforms to [`Content`](https://api.vapor.codes/vapor/latest/Vapor/Protocols/Content.html) you can return the result of the Fluent query directly.
|
|
|
|
|
|
## Read
|
|
|
|
To read models from the database, you can use [`query(on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE6create2on3NIO15EventLoopFutureCyxG11DatabaseKit0I11Connectable_p_tF) or [`find(_:on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE4find_2on3NIO15EventLoopFutureCyxSgG2IDQz_11DatabaseKit0J11Connectable_ptFZ).
|
|
|
|
### Find
|
|
|
|
The easiest way to find a single model is by passing its ID to [`find(_:on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE4find_2on3NIO15EventLoopFutureCyxSgG2IDQz_11DatabaseKit0J11Connectable_ptFZ).
|
|
|
|
```swift
|
|
Galaxy.find(42, on: conn)
|
|
```
|
|
|
|
The result will be a future containing an optional value. You can use [`unwrap(or:)`](https://api.vapor.codes/core/latest/Core/Extensions/Future.html#/s:3NIO15EventLoopFutureC4CoreAD12OptionalTypeRzlE6unwrap2orACy07WrappedG0QzGs5Error_pyXA_tF) to unwrap the future value or throw an error.
|
|
|
|
```swift
|
|
Galaxy.find(42, on: conn).unwrap(or: Abort(...))
|
|
```
|
|
|
|
### Query
|
|
|
|
You can use the [`query(on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE6create2on3NIO15EventLoopFutureCyxG11DatabaseKit0I11Connectable_p_tF) method to build database queries with filters, joins, sorts, and more.
|
|
|
|
```swift
|
|
Galaxy.query(on: conn).filter(\.name == "Milky Way")
|
|
```
|
|
|
|
### Filter
|
|
|
|
The [`filter(_:)`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC6filteryACyxq_GXDAA14FilterOperatorVyxq_GF) method accepts filters created from Fluent's operators. This provides a concise, Swifty way for building Fluent queries.
|
|
|
|
Calls to filter can be chained and even grouped.
|
|
|
|
```swift
|
|
Galaxy.query(on: conn).filter(\.mass >= 500).filter(\.type == .spiral)
|
|
```
|
|
|
|
Below is a list of all supported operators.
|
|
|
|
|operator|type|
|
|
|-|-|
|
|
|`==`|Equal|
|
|
|`!=`|Not equal|
|
|
|`>`|Greater than|
|
|
|`<`|Less than|
|
|
|`>=`|Greater than or equal|
|
|
|`<=`|Less than or equal|
|
|
|
|
By default, all chained filters will be used to limit the result set. You can use filter groups to change this behavior.
|
|
|
|
```swift
|
|
Galaxy.query(on: conn).group(.or) {
|
|
$0.filter(\.mass <= 250).filter(\.mass >= 500)
|
|
}.filter(\.type == .spiral)
|
|
```
|
|
|
|
The above query will include results where the galaxy's mass is below 250 _or_ above 500 _and_ the type is spiral.
|
|
|
|
### Range
|
|
|
|
You can apply Swift ranges to a query builder to limit the result set.
|
|
|
|
```swift
|
|
Galaxy.query(on: conn).range(..<50)
|
|
```
|
|
|
|
The above query will include only the first 50 results.
|
|
|
|
For more information on ranges, see docs for Swift's [Range](https://developer.apple.com/documentation/swift/range) type.
|
|
|
|
### Sort
|
|
|
|
Query results can be sorted by a given field.
|
|
|
|
```swift
|
|
Galaxy.query(on: conn).sort(\.name, .descending)
|
|
```
|
|
|
|
You can sort by multiple fields to perform tie breaking behavior where there is duplicate information in the one of the sorted fields.
|
|
|
|
### Join
|
|
|
|
Other models can be joined to an existing query in order to further filter the results.
|
|
|
|
```swift
|
|
Galaxy.query(on: conn).join(\Planet.galaxyID, to: \Galaxy.id)
|
|
.filter(\Planet.name == "Earth")
|
|
```
|
|
|
|
Once a table has been joined using [`join(_:to:)`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderCA2A14JoinSupportingRzrlE4join_2to6methodACyxq_GXDs7KeyPathCyqd__qd_0_G_AJyqd_1_qd_2_G0bD6MethodQztr2_lF), you can use fully-qualified key paths to filter results based on data in the joined table.
|
|
|
|
The above query fetches all galaxies that have a planet named Earth.
|
|
|
|
You can even decode the joined models using [`alsoDecode(...)`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC10alsoDecodeyACyxq__qd__tGqd__mAA5ModelRd__lF).
|
|
|
|
```swift
|
|
Galaxy.query(on: conn)
|
|
// join Planet and filter
|
|
.alsoDecode(Planet.self).all()
|
|
```
|
|
|
|
The above query will decode an array of `(Galaxy, Planet)` tuples.
|
|
|
|
### Fetch
|
|
|
|
To fetch the results of a query, use [`all()`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC3all3NIO15EventLoopFutureCySayq_GGyF), [`chunk(max:closure:)`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC5chunk3max7closure3NIO15EventLoopFutureCyytGSi_ySayq_GKctF), [`first()`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC5first3NIO15EventLoopFutureCyq_SgGyF) or an aggregate method.
|
|
|
|
#### All
|
|
|
|
The most common method for fetching results is with `all()`. This will return all matching results according to any fliters applied.
|
|
|
|
```swift
|
|
Galaxy.query(on: conn).all()
|
|
```
|
|
|
|
When combined with [`range(_:)`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC5rangeyACyxq_GXDSnySiGF), you can efficiently limit how many results are returned by the database.
|
|
|
|
```swift
|
|
Galaxy.query(on: conn).range(..<50).all()
|
|
```
|
|
|
|
#### Chunk
|
|
|
|
For situations where memory conservation is important, use [`chunk(...)`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC5chunk3max7closure3NIO15EventLoopFutureCyytGSi_ySayq_GKctF). This method returns the result set in multiple calls of a maximum chunk size.
|
|
|
|
```swift
|
|
Galaxy.query(on: conn).chunk(max: 32) { galaxies in
|
|
print(galaxies) // Array of 32 or less galaxies
|
|
}
|
|
```
|
|
|
|
#### First
|
|
|
|
The [`first()`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC5first3NIO15EventLoopFutureCyq_SgGyF) method is a convenience for fetching the first result of a query. It will automatically apply a range restriction to avoid transferring unnecessary data.
|
|
|
|
```swift
|
|
Galaxy.query(on: conn).filter(\.name == "Milky Way").first()
|
|
```
|
|
|
|
This method is more efficient than calling `all` and getting the first item in the array.
|
|
|
|
## Update
|
|
|
|
After a model has been fetched from the database and mutated, you can use [`update(on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE6update2on10originalID3NIO15EventLoopFutureCyxG11DatabaseKit0K11Connectable_p_0F0QzSgtF) to save the changes.
|
|
|
|
```swift
|
|
var planet: Planet ... // fetched from database
|
|
planet.name = "Earth"
|
|
planet.update(on: conn)
|
|
```
|
|
|
|
## Delete
|
|
|
|
After a model has been fetched from the database, you can use [`delete(on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE6delete5force2on3NIO15EventLoopFutureCyytGSb_11DatabaseKit0J11Connectable_ptF) to delete it.
|
|
|
|
```swift
|
|
var planet: Planet ... // fetched from database
|
|
planet.delete(on: conn)
|
|
```
|