使用 Knex.js 创建嵌套返回模型

Chr*_*her 3 javascript node.js knex.js hapi.js

我正在使用 Knex.js 在 Hapi.js 路由中查询 MySQL 数据库。以下代码有效,但需要嵌套查询:

{
    path: '/recipes',
    method: 'GET',
    handler: (req, res) => {
        const getOperation = Knex.from('recipes')
        // .innerJoin('ingredients', 'recipes.guid', 'ingredients.recipe')
        .select()
        .orderBy('rating', 'desc')
        .limit(10)
        .then((recipes) => {
            if (!recipes || recipes.length === 0) {
                res({
                    error: true,
                    errMessage: 'no recipes found'
                });
            }

            const recipeGuids = recipes.map(recipe => recipe.guid);
            recipes.forEach(r => r.ingredients = []);
            const getOperation2 = Knex.from('ingredients')
                .whereIn('recipe', recipeGuids)
                .select()
                .then((ingredients) => {
                    recipes.forEach(r => {
                        ingredients.forEach(i => {
                            if (i.recipe === r.guid) {
                                r.ingredients.push(i);
                            }
                        });
                    });
                    res({
                        count: recipes.length,
                        data: recipes
                    });
                });
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法使用 Knex.js 创建一个返回模型,该模型具有与父级的 id/guid 匹配的嵌套对象,以便我没有嵌套的承诺?

Gar*_*ryL 5

简短的回答:没有。

使用 Knex,您可以像使用 SQL 一样检索数据,它是基于记录的,而不是基于对象的,因此最接近的是使用连接来允许仅执行单个选择来检索具有元素的单个数组:食谱、指南、配料。这将重复每种成分的配方和指南,您可以通过使用嵌套对象来避免这种情况。(有关此示例,请参阅@Fazal 下面的答案。)

作为另一种选择,您可以将成分存储为配方表中的“blob”字段,但我不相信 MySQL 会允许您创建数组字段,因此在检索数据时,您必须进行转换的字段到数组中。并在将其更新到表中之前将其从 Array 转换。喜欢:storableData = JSON.stringify(arrayData)arrayData = JSON.parse(storableData)

不过,我建议还有其他一些事情可以帮助您改进代码。(是的,我知道,这里不是真正的问题):

  1. 将路由功能与数据处理分开。
  2. 此外,将数据操作功能与检索分开。
  3. 使用 throw 和 .catch 来创建和处理不成功的响应。

路由、数据检索、数据操作的分离使测试、调试和未来的理解更容易,因为每个功能都有更原子的目的。

抛出/.捕获不成功的过程条件通过允许您(大多数情况下)将单个 .catch 放入路由器响应处理中(Hapi.js 甚至可以为您执行此 .catch ? ??)。

此外,看到其他.catch.on('query-error'我添加记录错误。您可能想要使用不同的日志记录机制而不是控制台。我用温斯顿。请注意,这.on('query-error'不是 .catch。仍然会抛出一个 Error() ,并且必须在某处处理,这只会为您提供有关靠近源的故障的良好信息。

(抱歉,以下代码未经测试)

path: '/recipes',
method: 'GET',
handler: (req, res) => {
        return getRecipeNIngredients()
            .then((recipes) => {
                res({
                    count: recipes.length,
                    data: recipes
                });
            })
            .catch((ex) => {
                res({
                    error: true,
                    errMessage: ex.message
                });
            });
};

    function getRecipeNIngredients() {
        let recipes = null;
        return getRecipes()
            .then((recipeList) => {
                recipes = recipeList;
                const recipeGuids = recipes.map(recipe => recipe.guid);
                recipes.forEach(r => r.ingredients = []);
                return getIngredients(recipeGuids);
            })
            .then((ingredients) => {
                recipes.forEach(r => {
                    ingredients.forEach(i => {
                        if (i.recipe === r.guid) {
                            r.ingredients.push(i);
                        }
                    });
                });
                return recipes;
            })
            .catch((ex) => {
                console.log(".getRecipeNIngredients ERROR ex:",ex); // log and rethrow error.
                throw ex;
            });
    };

    function getRecipes() {
        return Knex.from('recipes')
            // .innerJoin('ingredients', 'recipes.guid', 'ingredients.recipe')
            .select()
            .orderBy('rating', 'desc')
            .limit(10)
            .on('query-error', function(ex, obj) {
                console.log("KNEX getRecipes query-error ex:", ex, "obj:", obj);
            })
            .then((recipes) => {
                if (!recipes || recipes.length === 0) {
                    throw new Error('no recipes found')
                }
            })
    };
    function getIngredients(recipeGuids) {
        return Knex.from('ingredients')
            .whereIn('recipe', recipeGuids)
            .select()
            .on('query-error', function(ex, obj) {
                console.log("KNEX getIngredients query-error ex:", ex, "obj:", obj);
            })
    };
Run Code Online (Sandbox Code Playgroud)

我希望这是有用的!加里。