Env: Vapor/Fluent 4.0.0
I have a tree structured data with model like this:
final class Ingredient: Model {
static let schema = "ingredients"
@ID(key: "id")
var id: UUID?
@Field(key: "name")
var name: String
@OptionalParent(key: "parent_id")
var parent: Ingredient?
@Children(for: \.$parent)
var children: [Ingredient]
}
And I want to return the whole tree as a JSON in one of API methods.
func index(req: Request) throws -> EventLoopFuture<[APIIngredient]> {
// Gathering top-level nodes without parents
let ingredients = try Ingredient.query(on: req.db)
.filter(\.$parent.$id == nil)
.sort(\.$name)
.all()
.wait()
enter code here
// Creating API models
let apiIngredients = try ingredients.map {
try APIIngredient(
ingredient: $0,
childrenGetter: {
try $0.$children.query(on: req.db).all().wait()
}
)
}
return req.eventLoop.future(apiIngredients)
}
But I've found that.wait() is disallowed to use in request handlers. What's the right way to approach this?
wait()
is not allowed because it blocks the EventLoop. So you have a few options:
Use eager loading as suggested by Nick. This will be much more efficient as it's only 2 DB queries instead of N+1.
Use async/await to write it how you want
Handle the futures properly. Instead of using wait()
switch to handling the futures:
func index(req: Request) throws -> EventLoopFuture<[APIIngredient]> {
// Gathering top-level nodes without parents
return Ingredient.query(on: req.db)
.filter(\.$parent.$id == nil)
.sort(\.$name)
.all()
.flatMap { ingredients in
ingredients.map { ingredient -> EventLoopFuture<APIIngredient>
let future = ingredient.$children.query(on: req.db).all().map { children in
APIIngredient(ingredient: ingredient, children: children)
}
}.flatten(on: req.eventLoop)
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.