简体   繁体   中英

Querying nested children in Vapor's Fluent

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:

  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. Use async/await to write it how you want

  3. 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.

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