Обновление атрибутов в связанных моделях с использованием 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() после определения моих моделей? Я не понимаю, что именно он должен делать. Я могу получить свой объект с ассоциациями без него. Я добавил его в свой код в отчаянии, чтобы получить обновления, но я не уверен, действительно ли это необходимо.

Спасибо

Ответы

Ответ 1

На ваш вопрос:

Когда вы с нетерпением загружаете 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 - это асинхронная операция, поэтому выполнение secelize.sync без привязки обратного вызова не рекомендуется. Кроме того, похоже, что вы выполняете синхронизацию в определении модели - вы должны делать это только один раз, предпочтительно в том месте, где вы определяете свои модели.
  • Похоже, вы определяете несколько моделей в одном файле - вы должны определять только один в каждом файле. Ассоциации можно настроить, выполнив sequelize.import([путь к модели фильтра) в файле FilterContent или сделав все ассоциации в месте импорта своих моделей в ваше приложение.

изменить ответ на ваш комментарий:

Вы не можете выполнить один вызов функции, который будет обновлять фильтр и фильтровать содержимое, но вам также не нужно делать обновления в последовательности. Вы можете выпустить все команды обновления, не дожидаясь их завершения.

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

})

Таким образом, все запросы будут выполняться параллельно, и ваша функция будет вызываться, когда все они будут завершены. Обратите внимание, что я использовал spread здесь, чтобы вернуть массив из Promise.all в отдельные аргументы.

Ответ 2

Здравствуйте, @Jan Aagaard Meier может помочь мне, моя вторая и обновленная таблица следует моему коду, мне действительно нужно решить эту проблему, что я могу делать неправильно?

Мои отношения между двумя профилями и таблицами модулей профиля Модуль профиля имеет ключ profileId, где он связан с ProfileId Profile, а у меня есть поле ModuleId:

models.Profile_Module.belongsTo(models.Profile, { foreignKey: "profileId" });
models.Profile.hasMany(models.Profile_Module, {
  foreignKey: "profileId",
  sourceKey: "profileId",
  as: "pr"
});

Мой метод кода:

async function update(data, profileId) {


  models.Profile.findOne({
    where: {
      profileId: profileId
    },
    attributes: {
      exclude: ["customerId", "profileDeletedUser", "profileDeletedDate"]
    },
    raw: true,
    include: [
      {
        model: models.Profile_Module,
        required: true,
        as: "pr"
      }
    ]
  })
    .then(function(prof) {
      return Promise.all([
        models.Profile.update(
          {
            profileName: data.profileName,
            profileDescription: data.profileDescription
          },
          {
            where: { profileId: profileId }
          }
        ),
        models.pr.map(fc =>
          fc.update(
            { moduleId: data.modules.moduleId },
            { where: { profileId: profileId } }
          )
        )
      ]);
    })
    .then(console.log)
    .catch(console.log);
  // .spread(function(prof, pr) {
  //   return filter;
  // });
}

Тело моего запроса:

{
  "profileName": "Teste",
  "profileDescription": "Teste profile description",
   "modules":[
      {
         "moduleId":1
      },
      {
         "moduleId":2
      }
   ]
}