2017-11-27 23 views
0

Knex.jsを使用して、Hapi.jsルートのMySQLデータベースをクエリしています。次のコードは動作しますが、ネストされたクエリが必要です。Knex.jsを使用してネストされたリターンモデルを作成する

{ 
    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 
        }); 
       }); 
     }); 
    } 
} 

親のidが/のguid一致するオブジェクトを入れ子になったKnex.jsと帰りのモデルを作成する方法はありますが私はネストされた約束を持っていないこと?

答えて

1

短い答え:Knex付番

、あなたがデータに記録に基づいているSQLと同じを取得することができ、ベースのオブジェクトなので、あなたが来ることができている最も近いができるように結合を使用することですありませんレシピ、ガイド、成分などの要素を持つ単一の配列を取得するための単一のselectを実行します。これにより、各成分のレシピ& guidが繰り返されます。これは、ネストされたオブジェクトを使用することによって回避されます。 (この例については、@Fazalの答えを参照してください。)

また、レシピテーブルに「blob」フィールドとして成分を保存することもできますが、MySQLが許可するとは思わないArrayフィールドを作成するため、データを取得するときにフィールドの配列への変換を行う必要があります。それをテーブルに更新する前に、配列から変換してください。 Like:storableData = JSON.stringify(arrayData)arrayData = JSON.parse(storableData)

コードの改善に役立ついくつかの点がありますが、 (ええ、私は知っている、実際にはここに質問がない):

  1. データ処理からルーティング機能を分離する。
  2. また、検索からデータ操作機能を分離します。
  3. 失敗した応答を作成して処理するには、& .catchを使用してください。

ルーティング、データ検索、データ操作の分離は、各機能がより基本的な目的を持つため、テスト、デバッグ、および将来の理解を容易にします。

失敗したプロセス条件を投げたり投じたりすると、ルータの応答処理(たいていはHapi.jsがこれを実行することがあります)に1つの.catchを入れることができるため、より包括的なエラー処理が簡単になります。あなたのためにキャッチ???)。

また、ログエラーのために追加した.catchおよび.on('query-error'も参照してください。コンソールではなく、使用するロギング・メカニズムが異なる場合があります。私はWinstonを使用します。 .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); 
      }) 
    }; 

私は、これは便利ですね! ゲーリー。

0

ネストクエリーは簡単に回避できます。サブクエリを次のように使用してください:

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); 
    }) 

関連する問題