在 Vapor 的 Fluent 中查询嵌套子项
Querying nested children in Vapor's Fluent
环境:Vapor/Fluent4.0.0
我有一个树状结构数据,其模型如下:
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]
}
我想 return 整个树作为 JSON 中的一种 API 方法。
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: [=11=],
childrenGetter: {
try [=11=].$children.query(on: req.db).all().wait()
}
)
}
return req.eventLoop.future(apiIngredients)
}
但我发现 .wait() 不允许在请求处理程序中使用。解决这个问题的正确方法是什么?
wait()
是不允许的,因为它会阻塞 EventLoop。所以你有几个选择:
按照 Nick 的建议使用预先加载。这将更加有效,因为它只有 2 个数据库查询而不是 N+1 个。
用async/await随心所欲地写
妥善处理期货。而不是使用 wait()
切换到处理期货:
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)
}
}
环境:Vapor/Fluent4.0.0
我有一个树状结构数据,其模型如下:
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]
}
我想 return 整个树作为 JSON 中的一种 API 方法。
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: [=11=],
childrenGetter: {
try [=11=].$children.query(on: req.db).all().wait()
}
)
}
return req.eventLoop.future(apiIngredients)
}
但我发现 .wait() 不允许在请求处理程序中使用。解决这个问题的正确方法是什么?
wait()
是不允许的,因为它会阻塞 EventLoop。所以你有几个选择:
按照 Nick 的建议使用预先加载。这将更加有效,因为它只有 2 个数据库查询而不是 N+1 个。
用async/await随心所欲地写
妥善处理期货。而不是使用
wait()
切换到处理期货:
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)
}
}