简体   繁体   English

在 Vapor 的 Fluent 中查询嵌套的子级

[英]Querying nested children in Vapor's Fluent

Env: Vapor/Fluent 4.0.0环境:蒸汽/流利的 4.0.0

I have a tree structured data with model like this:我有一个带有 model 的树状结构数据,如下所示:

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.我想在 API 方法之一中将整个树作为 JSON 返回。

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.但我发现 .wait() 不允许在请求处理程序中使用。 What's the right way to approach this?解决这个问题的正确方法是什么?

wait() is not allowed because it blocks the EventLoop. wait()是不允许的,因为它阻塞了 EventLoop。 So you have a few options:所以你有几个选择:

  1. Use eager loading as suggested by Nick.按照尼克的建议使用急切加载。 This will be much more efficient as it's only 2 DB queries instead of N+1.这将更有效率,因为它只有 2 个 DB 查询而不是 N+1。

  2. Use async/await to write it how you want使用 async/await 来写你想要的

  3. Handle the futures properly.妥善处理期货。 Instead of using wait() switch to handling the futures:而不是使用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)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM