Reputation: 47
I have the following relations: A container can have many question entities and a question entity can have many answers. In the Vapor/Fluent documentation I can only find examples with Parent and Childs but not Parent - Child - ChildChild. Can someone give me a hint?
Upvotes: 1
Views: 702
Reputation: 699
As mentioned by @0xTim, there is a plethora of ways to access relational data with, well, relational databases! Including but not limited to:
Eager Loading Code Example:
The simplest way (in my opinion) is eager loading. Eager loading on a database query allows you to query for a root Model schema and load all the relationships you need in one go.
This is some amazing typecasting magic in Swift, and like wow Vapor, y'all are doing some amazing work!
Take the following schema from the oh-so-wonderful Vapor docs:
final class Galaxy: Model {
static let schema = "galaxies"
@ID(key: .id) var id: UUID?
@Field(key: "name") var name: String
// Notice there is no relationship defined here.
init() { }
init(id: UUID? = nil, name: String) {
self.id = id
self.name = name
}
}
final class Star: Model, Content {
static let schema = "stars"
@ID(key: .id) var id: UUID?
@Field(key: "name") var name: String
// Parent relationship to Galaxy
@Parent(key: "galaxy_id") var galaxy: Galaxy
init() { }
init(id: UUID? = nil, name: String, galaxyID: UUID) {
self.id = id
self.name = name
self.$galaxy.id = galaxyID
}
}
final class Planet: Model {
static let schema = "planets"
@ID(key: .id) var id: UUID?
@Field(key: "name") var name: String
// Parent relationship to Star
@Parent(key: "star_id") var star: Star
init() { }
init(id: UUID? = nil, name: String) {
self.id = id
self.name = name
}
}
So now say you want to load a specific planet, and then access the (nested) star's (nested) galaxy value:
app.get("planet/{id}") { request async throws -> Planet
guard
let planetIdString = try request.parameters.get("id"),
let planetId = UUID(uuidString: planetIdString)
else {
throw Abort(.notFound)
}
guard let planet = try await Planet.query(on: database) // <~ Create a query for all Planets
.filter(\.$id == planetId) // <~ Get the planets with a matching ID
.with(\.$star) { star in // <~ Load the nested Star
star.with(\.$galaxy) // <~ Load the nested Galaxy
}
.limit(1) // <~ Assure only one Planet is returned
.all() // <~ Return all results
.first
else {
throw Abort(.internalError)
}
// For demo purposes, print out the nested data.
print(planet.star.galaxy)
}
Upvotes: 3