1. ホーム
  2. mysql

[解決済み] Sequelize:イーガーロードする方法、関連付け、生:真?

2022-02-16 17:48:52

質問内容

Node.jsでのイager loadingは、Sequelizeを使用する唯一の方法です。私は、ネストされたインクルードを持つMySQL DBからすべてのユーザー調査データをエクスポートしようとしています。アンケートの回答は500k行以上あり、私のスクリプトは、返されたすべての行のインスタンスを作成するためにメモリ不足でクラッシュしています。

クエリを "raw" にして、単純なオブジェクトデータだけを取得したいのですが、そうすると、各インクルードの最初の関連レコードだけを返し、それらをすべて含む配列は返されません。すべての関連レコードを取得し、それをrawにする方法はありますか?それとも、Sequelizeは大規模なクエリのためにこの方法を使用することは想定されていないのでしょうか?以下は私のクエリです。

db.User.findAll({
  include: [
    { model: db.Referrer }, // has one Referrer
    { model: db.Individual }, // has many Individuals (children)
    {
      model: db.UserSurvey, // has many UserSurveys
      include: {
        model: db.Answer, // UserSurveys have many Answers
        include: {
          model: db.Question // survey question definition
        }
      }
    }
  ],
  raw: true // only returns first Individual, UserSurvey, Answer, etc.
  nest: true // unflattens but does not fix problem
})


このクエリは、返される行を制限すれば問題なく動作します。制限しない場合は、データセットの大きさによってクラッシュするだけです。トップレベルや様々なインクルード内のあらゆる場所にrawを追加してみましたが、何もうまくいかないようです。クエリを Answer に基づいて、すべてのリレーションシップが単一のレコードを必要とするようにすればよいのでしょうか?それとも、これらの複雑なクエリを raw にして、すべての関連レコードを含める方法があるのでしょうか?読んでくれてありがとう、これは私が数日間困っていたことです。

どのように解決するのですか?

Sequelizeのドキュメントにあるように raw オプションを使用します。

sequelize はクエリの結果をフォーマットしようとしません。 のインスタンスを作成します。

つまり、1つのメインレコードと2つの関連レコードがある場合、SequelizeがSQL-queryから取得するものなので、2つのレコードが取得されます。

あなたの場合は limitoffset オプションを循環させて、チャンク単位でレコードを取得します。そうすれば、メモリ不足になることはないだろう。

また、モデルの代わりにプレーンなオブジェクトを取得するには get({ plain: true }) というように、各モデルに対して

const users = db.User.findAll({
  include: [
    { model: db.Referrer }, // has one Referrer
    { model: db.Individual }, // has many Individuals (children)
    {
      model: db.UserSurvey, // has many UserSurveys
      include: {
        model: db.Answer, // UserSurveys have many Answers
        include: {
          model: db.Question // survey question definition
        }
      }
    }
  ]
})
const plainUsers = users.map(x => x.get({ plain: true }))