web-dev-qa-db-ja.com

Sequelizeを使用して関連モデルの属性を更新する

親モデルと関連モデルの両方の属性を一度に更新できますか?私はそれを動作させるのに問題があり、完全な例を見つけることができませんでした。それが私のコードに何か問題があるのか​​、それとも私が期待するように動作するように意図されていたのかはわかりません。 onUpdate: 'cascade'をhasMany定義に追加してみましたが、何も実行されていないようです。

モデル:

module.exports = function( sequelize, DataTypes ) {
var Filter = sequelize.define( 'Filter', {
    id : {
            type : DataTypes.INTEGER,
            autoIncrement : true,
            primaryKey : true
         },
        userId : DataTypes.INTEGER,
        filterRetweets : DataTypes.BOOLEAN,
        filterContent : DataTypes.BOOLEAN
    },
    {
        tableName : 'filter',
        timestamps : false
    }
);

var FilteredContent = sequelize.define( 'FilteredContent', {
        id : {
                type : DataTypes.INTEGER,
                autoIncrement : true,
                primaryKey : true
        },
        filterId : {
                        type : DataTypes.INTEGER,
                        references : "Filter",
                        referenceKey : "id"
        },
        content : DataTypes.STRING
    },
    {
        tableName : "filteredContent",
        timestamps : false
    }
);

Filter.hasMany( FilteredContent, { onUpdate : 'cascade', as : 'filteredContent', foreignKey : 'filterId' } );
sequelize.sync();

    return {
        "Filter" : Filter,
        "FilteredContent" : FilteredContent
    };
}

フィルターを取得し、関連付けられたFilteredContentオブジェクトの属性を更新しようとしています。

Filter.find({   where: { id: 3 }, 
            include: [ { model : FilteredContent, as : 'filteredContent' } ] 
}).success ( function( filter ) {
    var filteredContent = FilteredContent.build( {
        filterId : filter.id,
        id : 2,
        content : 'crap'
    });
    filter.save();
});

これにより、Filterオブジェクトの属性のみが更新されます。 FilteredContentの属性も更新するにはどうすればよいですか?

また、モデルを定義した後にsequelize.sync()が必要ですか?それが何をすることになっているのか正確にはわかりません。オブジェクトを関連付けなしで取得できます。更新を機能させるために必死にコードに追加しましたが、それが実際に必要かどうかはわかりません。

ありがとう

19
jsparks

あなたの質問へ:

FilteredContentを(includeを使用して)熱心にロードすると、モデルインスタンスが既に構築されているため、buildを呼び出す必要はありません。これに沿った何かがあなたが望むことをするはずです:

Filter.find({
  where: { id: 3 }, 
  include: [ { model : FilteredContent, as : 'filteredContent' } ] 
}).then ( function( filter ) {
  return filter.filteredContent[0].updateAttributes({
    content: 'crap'
  })
}).then(function () {
  // DONE! :)
});

全体として投稿したコードに関するいくつかのポインタ:

  • sequelize.syncは、モデルがまだ存在しない場合、モデルのデータベーステーブルを作成します。テーブルがすでに存在する場合、何をしたいかには必要ありません
  • sequelize.syncは非同期操作であるため、コールバックをアタッチせずにsequelize.syncを実行することはお勧めできません。さらに、モデル定義で同期を行っているように見えます-モデルを定義する場所で1回だけ行う必要があります。
  • 1つのファイルで複数のモデルを定義しているようです。各ファイルで1つだけ定義する必要があります。関連付けは、FilterContentファイルでsequelize.import([path to filter model)]を実行するか、モデルをアプリにインポートする場所ですべての関連付けを行うことで設定できます。

コメントに回答するために編集します:

フィルターとfilteredcontentの両方を更新する単一の関数呼び出しを実行することはできませんが、更新を順番に実行する必要はありません。すべての更新コマンドは、それらが完了するのを待たずに発行できます。

Filter.find({
  where: { id: 3 }, 
  include: [ { model : FilteredContent, as : 'filteredContent' } ] 
}).then ( function( filter ) {
  return Promise.all([
    filter.updateAttributes({}),
    filter.filteredContent.map(fc => fc.updateAttributes({}))
  ]);
}).spread(function (filter, filteredContents) {

})

このようにして、すべてのクエリが並行して実行され、すべてのクエリが完了すると、then関数が呼び出されます。ここではspreadを使用して、Promise.allから返された配列を個別の引数に変換していることに注意してください。

25