我使用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
});
});
});
}
}是否有一种方法可以使用Knex.js创建一个返回模型,该模型的嵌套对象与父的id/guid相匹配,从而使我没有嵌套的承诺?
发布于 2017-11-28 01:20:50
简短回答:不。
使用Knex,您可以检索与SQL相同的数据,SQL是基于记录的,而不是基于对象的,所以您可以使用一个join来只进行一个选择来检索具有元素的单个数组:菜谱、guids、成分。这将重复每个成分的配方& guid,您可以通过使用嵌套对象来避免这种情况。(有关此问题的示例,请参见下面@Fazal的回答。)
作为另一种选择,您可以将成分作为“blob”字段存储在配方表中,但我不认为MySQL将允许您创建一个数组字段,因此在检索数据时,必须将字段转换为数组。并在将其更新到表之前将其从Array中转换出来。喜欢:storableData = JSON.stringify(arrayData)和arrayData = JSON.parse(storableData)
不过,我还建议您做一些其他的事情来帮助您改进代码。(是的,我知道,这并不是真正的问题):
路由、数据检索、数据操作的分离使得测试、调试和未来理解变得更加容易,因为每个功能都有更多的原子用途。
抛出/.捕获不成功的进程条件使得拥有更全面的错误处理变得更加简单,因为它允许您(大多数情况下)在路由器响应处理中放置一个.catch (Hapi.js甚至可以为您执行此.catch??)。
另外,请参阅我为日志记录错误添加的另一个.catch和.on('query-error'。您可能要使用不同的日志机制,而不是控制台。我用温斯顿。请注意,.on('query-error'不是.catch。仍然会抛出一个错误(),并且必须在某个地方进行处理,这只会给您提供与源附近的故障有关的良好信息。
(对不起,下面的代码未经测试)
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);
})
};我希望这是有用的!加里。
发布于 2019-11-26 08:56:42
我创建了一个库,它返回嵌套对象,即使它有类型的类型。
import * as n from 'nested-knex';
n.array(
n.type({
id: n.number("recipe.id", { id: true }),
title: n.string("recipe.title"),
ingredients: n.array(
n.type({
id: n.number("ingredients.id", { id: true }),
title: n.string("ingredients.title")
})
)
})
)
.withQuery(
knex
.from("recipes")
.innerJoin("ingredients", "recipes.guid", "ingredients.recipe")
.select()
.orderBy("rating", "desc")
.limit(10)
)
.then(recipes => {});所以菜谱甚至有类型

发布于 2017-11-28 18:16:56
您可以轻松地避免嵌套查询。只需使用子查询作为-
knex.select('*')
.from(function () {
this.select('*').from('recipes').limit(10).as('recipes'); // limit here
})
.leftJoin('ingredients', 'ingredients.recipe_id', 'recipes.guid')
.then((rec) => {
console.log(rec);
})你看..。只有几行代码。
https://stackoverflow.com/questions/47503627
复制相似问题