Sequelize批量更新阵列问题

时间:2016-05-14 22:07:50

标签: node.js sequelize.js

我有一个记录列表,我希望使用各个表单字段中的调整值进行批量更新。当我尝试运行POST并根据输入中的值更新记录时,我在Where子句中遇到错误,我想知道如何解析where discoverySourceId的where子句或者什么将是我当前设置中使用的最佳方法。

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

2 个答案:

答案 0 :(得分:2)

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>

答案 1 :(得分: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' });
    });

因此,所有更新的记录都将作为一个对象数组返回,您可以使用该数据执行任何操作。