2016-05-14 2 views
0

У меня есть список записей, которые я ищу для массового обновления с установленными значениями в отдельных полях формы. Когда я пытаюсь запустить POST и обновлять записи на основе значений во входе, я сталкиваюсь с ошибкой в ​​предложении Where, и мне интересно, как я могу проанализировать значение discoverySourceId для предложения where или что было бы лучшим метод для использования с моей текущей настройкой.Sequelize Bulk Update Array Issue

Error: Missing where attribute in the options parameter passed to update. 

Маршрут:

var appRoutes = express.Router(); 
var _ = require('lodash-node'); 
var async = require('async'); 
var models = require('../models/db-index'); 

    appRoutes.route('app/settings/discovery-sources') 

    .get(function(req, res){ 
     models.DiscoverySource.findAll({ 
       where: { 
        organizationId: req.user.organizationId 
       }, attributes: ['discoverySourceId', 'discoverySourceName'] 
      }).then(function(discoverySource){ 
      res.render('pages/app/settings-discovery-sources.hbs', { 
       discoverySource: discoverySource 
      }); 
     }) 
    }) 
     .post(function(req, res){ 
       console.log('POST Triggered'); 
       var sources = _.map(req.body.discoverySourceName, function (source) { 
        return { 
         discoverySourceName: source, 
         discoverySourceId: req.body.discoverySourceId 
        }; 
       }); 
       models.DiscoverySource.update(sources).then(function(){ 
        console.log("Successful update"); 
        res.redirect('/settings/discovery-sources'); 
       }); 
      }); 

**Form:** 

    <div class="row"> 
     <div class="col-md-8 col-md-offset-2"> 
      <div class="annotation-form"> 
       <h2>Discovery Sources</h2> 
       <form action="/app/settings/discovery-sources" method="post"> 
       {{#each discoverySource}} 
        <input type="hidden" name="discoverySourceId" value={{this.discoverySourceId}}> 
        <input type="text" name="discoverySourceName[0]" value="{{this.discoverySourceName}}"><a href="#" id="settings-delete-discovery-source">Delete</a> 
        <br /> 
       {{else}} 
        <p>No Discovery Sources</p> 
       {{/each}} 
        <button type="submit">Update Sources</button> 
       </form> 
      </div> 
     </div> 
    </div> 

discoverySource:

module.exports = function(sequelize, DataTypes) { 

var DiscoverySource = sequelize.define('discovery_source', { 
    discoverySourceId: { 
     type: DataTypes.INTEGER, 
     field: 'discovery_source_id', 
     autoIncrement: true, 
     primaryKey: true, 
     notNull: true, 
    }, 
    discoverySourceName: { 
     type: DataTypes.STRING, 
     field: 'discovery_source_name' 
    }, 
    organizationId: { 
     type: DataTypes.TEXT, 
     field: 'organization_id' 
    }, 
},{ 
    freezeTableName: true 
}); 
    return DiscoverySource; 
} 
+0

Вам не хватает предложения where в вызове обновления. Передайте organizationId в предложение where, иначе он обновит каждую отдельную строку в таблице DiscoverySource. – grimurd

+0

Как включить предложение where? Я попробовал 'models.DiscoverySource.update (sources, {where: {discoverySourceId: req.body.discoverySourceId}}), но получил' Unhandled rejection TypeError: build.set не является ошибкой функции – cphill

+0

Я угадываю здесь , но req.body.discoverySourceId скорее всего является строковым типом, а не типом Number (поскольку скрытые входы анализируются как строки, а не числа). Попробуйте parseInt (req.body.discoverySourceId) – grimurd

ответ

3
var appRoutes = express.Router(); 
var _ = require('lodash-node'); // just use lodash, using lodash-node is deprecated and it's redundant. 
var async = require('async'); 
var models = require('../models/db-index'); 

// Added these for context 
var app = express(); 
var Promise = require('bluebird'); // or Q if you prefer. 

// Make sure you're using body-parser urlencoded 
// with extended set to true. This allows us to have 
// fancy body parsing for forms. 
// This line must be above all your routes. 
var bodyParser = require('body-parser'); 
app.use(bodyParser.urlencoded({ 
    extended: true 
})) 

appRoutes.route('app/settings/discovery-sources') 
    .get(function (req, res) { 
     models 
      .DiscoverySource 
      .findAll({ 
       where: { 
        organizationId: req.user.organizationId 
       }, 
       attributes: ['discoverySourceId', 'discoverySourceName'] 
      }) 
      .then(function (discoverySource) { 
       res.render('pages/app/settings-discovery-sources.hbs', { 
        discoverySource: discoverySource 
       }); 
      }) 
    }) 
    .post(function (req, res) { 
     console.log('POST Triggered'); 
     // We use promise.map to map the array in the body into an array of promises 
     // which are resolved when each promise has been resolved. 
     // It's a good idea here to use sequelize.transaction() so that if one update 
     // fails, everything gets rolled back. 
     // If you're using Q it doesn't support .map() so this looks slightly different in that case. 
     // q.all(_.map(req.body.discoverySources, function() {})) 
     Promise 
      .map(req.body.discoverySources, function (source) { 
       return models 
        .DiscoverySource 
        .update({ 
         discoverySourceName: source.name 
        }, { 
         // We have to call update with the ID of each discoverySource so that 
         // we update the names of each discovery source correctly. 
         where: { 
          discoverySourceId: source.id 
         } 
        }) 
      }) 
      .then(function() { 
       console.log("Successful update"); 
       res.redirect('/settings/discovery-sources'); 
      }); 
    }); 

HTML

<div class="row"> 
    <div class="col-md-8 col-md-offset-2"> 
     <div class="annotation-form"> 
      <h2>Discovery Sources</h2> 
      <form action="/app/settings/discovery-sources" method="post"> 
       {{#each discoverySource}} 
       <!-- Use body parser urlencoded syntax so the request body is parsed into an array of objects with the 
       properties id and name. See the qs library for syntax documentation, https://www.npmjs.com/package/qs#readme --> 
       <input type="hidden" name="discoverySources[][id]" value={{this.discoverySourceId}}> 
       <input type="text" name="discoverySources[][name]" value="{{this.discoverySourceName}}"><a href="#" id="settings-delete-discovery-source">Delete</a> 
       <br /> {{else}} 
       <p>No Discovery Sources</p> 
       {{/each}} 
       <button type="submit">Update Sources</button> 
      </form> 
     </div> 
    </div> 
</div> 
+0

Спасибо за ответ, и это, безусловно, лучший подход, но я столкнулся с ошибкой: 'Unhandled rejection SequelizeValidationError: нарушение строки: discoverySourceName не может быть массивом или объектом'. Любые мысли об этой ошибке? Является ли это в основном указанием на то, что мне нужно пройти через метод .update() 'на стороне маршрута, а не передавать элементы в массив в представлении? – cphill

+0

Нет, наверное, ошибка в html, которую я написал. Сделайте консоль.войдите в req.body в почтовом маршруте и проверьте, имеет ли он массив объектов с указанными двумя свойствами. Похоже, что opensysourcename - это массив по какой-то причине. – grimurd

+0

Какой шаблон двигателя вы используете? Усы? – grimurd

0

Просто добавить на @GrimurD ответ - если при обновлении вы хотите получить обратно обновленные данные, которые вы можете сделать:

Promise 
    .all(_.map(clients, (client) => { 
     const { firstName, lastName, phoneNumber, emailAddress } = client; 
     return Client 
     .update({ 
      firstName, 
      lastName, 
      phoneNumber, 
      emailAddress, 
     }, { 
      where: { 
      id: client.id, 
      }, 
      returning: true, 
      plain: true, 
     }); 
    })) 
    .then((results) => { 
     // do whatever you want with the returned results 
     const updatedClients = results.map(result => _.omit(result[1].dataValues, ['salt', 'password'])); 
     callback(null, updatedClients); 
    }) 
    .catch((err) => { 
     callback({ error: true, message: err.message ? err.message : 'Unable to fetch updated user details' }); 
    }); 

Таким образом, все обновленные записи будут возвращены как массив объектов и вы можете делайте все, что хотите, с этими данными.