使用 Sequelize 在项目数组上创建/更新

Posted

技术标签:

【中文标题】使用 Sequelize 在项目数组上创建/更新【英文标题】:Create/update with Sequelize on an array of items 【发布时间】:2014-12-28 06:09:08 【问题描述】:

我创建了一个函数来:

获取一个“标签”数组并查看它们是否已经在数据库中有记录 创建那些不存在的, 并更新那些确实存在的内容 返回一个 json 数组报告每个项目,无论它们是更新/创建的,还是导致错误

我设法让它工作了,但我觉得我只是做了一些丑狗的晚餐!

var models = require("../models");
var Promise = models.Sequelize.Promise;

module.exports = 

    addBeans: function (req, callback) 

        Promise.map(req.body.beansArr, function (bean) 
            return models.Portfolio.findOrCreate(where: label: bean, label: bean);

        ).then(function (results)    // Array of 'instance' and 'created' for each bean "findOrCreate(where, [defaults], [options]) -> Promise<Instance>"
            var promisesArr = [];
            results.forEach(function (result) 
                if (result[1])    // result[1] = wasCreated
                    promisesArr.push(Promise.resolve([result[0].dataValues.label, "created"]));   
                 else 
                    promisesArr.push(
                        models.Portfolio.update(label: result[0].dataValues.label,
                            where: label: result[0].dataValues.label).then(function () 
                                return Promise.resolve([result[0].dataValues.label, "updated"])
                            )
                    );
                
            ); 
            return promisesArr;

        // When it's all done create a JSON response
        ).then(function (results) 
            var resultObj = items: [];  // JSON to return at the end
            Promise.settle(results).then(function (promiseinstances) 

                for (var i = 0; i < promiseInstances.length; i++) 
                    if (promiseInstances[i].isFulfilled()) 
                        resultObj.items.push(
                            item: 
                                label: promiseInstances[i].value()[0],
                                result: promiseInstances[i].value()[1],
                                error: ''
                            
                        );
                    
                    else if (promiseInstances[i].isRejected())
                        resultObj.items.push(
                            label: promiseInstances[i].value()[0],
                            result: 'error',
                            error: promiseInstances[i].reason()
                        );
                    
                

            // Send the response back to caller
            ).then(function () 
                return callback(null, resultObj);
            , function (e) 
                return callback(e, resultObj);
            );

        );
    

;

问题:

是否有更简单或更明显的方法来使用 Sequelize 创建/更新值? 我对@9​​87654322@ 的使用是否适合这种情况?我觉得我把它弄得比它需要的更复杂。

我是 Sequelize 和使用 Promises 的新手,如果有人能就此提出建议,我将不胜感激。

【问题讨论】:

【参考方案1】:

我觉得这在 CodeReview.SE 上会更好,但我可以看到一些问题。

是否有更简单或更明显的方法来使用 Sequelize 创建/更新值?

好吧,一方面:

.then(function(array)
   var newArr = [];
   array.forEach(function(elem)
       newArr.push(fn(elem);
   
   return newArr;
);

只是

.map(fn)

此外,promise 可以同化,因此您可以从 .then 转换为 return val;,而不必转换为 return Promise.resolve(val);

所以:

).then(function (results)    // Array of 'instance' and 'created' for each bean "findOrCreate(where, [defaults], [options]) -> Promise<Instance>"
    var promisesArr = [];
    results.forEach(function (result) 
        if (result[1])    // result[1] = wasCreated
            promisesArr.push(Promise.resolve([result[0].dataValues.label, "created"]));   
         else 
            promisesArr.push(
                models.Portfolio.update(label: result[0].dataValues.label,
                    where: label: result[0].dataValues.label).then(function () 
                        return Promise.resolve([result[0].dataValues.label, "updated"])
                    )
            );
        
    ); 
    return promisesArr;
)

只是

.map(function(result)
     if(result[1]) return [result[0].dataValues.label, "created"];
     return  models.Portfolio.update(label: result[0].dataValues.label,
                    where: label: result[0].dataValues.label).
                    return([result[0].dataValues.label, "updated"]);
 );

但是,由于您希望它在解决问题的情况下都能正常工作,因此您必须这样做:

.then(function(results)
     return results.map(function(result)
     if(result[1]) return [result[0].dataValues.label, "created"];
     return  models.Portfolio.update(label: result[0].dataValues.label,
                    where: label: result[0].dataValues.label).
                    return([result[0].dataValues.label, "updated"]);
 );
 );

这意味着无论如何它都会解决,然后你会打电话给.settle()

.settle().then(function(results)
     // your settle logic here
);

注意最后一个:

).then(function () 
    return callback(null, resultObj);
, function (e) 
    return callback(e, resultObj);
);

很简单:

.nodeify(callback);

但是,我建议坚持承诺。

【讨论】:

感谢一百万!一个问题:“承诺同化”是什么意思?我虽然用'return val;'我将 'val' 作为参数传递给使用 'then' 展开的函数(例如:.then(function(val)); ),并使用 'Promise.resolve(val)' 我通过了 promise? Promise.resolve 将在您在 then 中返回的所有内容上被隐式调用。【参考方案2】:

我将 Promise.settle 用于 sequelize.update,并且可以通过 _settledValueField 获取影响行数。

promise.push(...update...)

db.sequelize.Promise.settle(promise).then(function (allresult) 
    var affectcnt = 0
    allresult.forEach(function (singlecnt) 
      if (undefined !== singlecnt._settledValueField[1]) 
        affectcnt += parseInt(singlecnt._settledValueField[1])
      
    )

不幸的是,它仅适用于更新。

【讨论】:

它看起来像部分答案。请尝试将其合并为完整的答案【参考方案3】:

您可以使用 sequelize 在数据库中插入数组。您想更改模型,如下所示。我正在尝试通过数组在数据库中添加多种语言。

language:  type: DataTypes.STRING, 
          allowNull: false,
          get() 
          
         return this.getDataValue('language').split(';') 
         , 
        set(val)
        
        this.setDataValue('language',Array.isArray(val) ? val.join(','):val);

      
     

【讨论】:

以上是关于使用 Sequelize 在项目数组上创建/更新的主要内容,如果未能解决你的问题,请参考以下文章

Sequelize - 从数组批量创建

sequelize更新事务锁定行

如何使用 Sequelize + PostgreSQL 将项目附加到数组值

如何在使用 Sequelize 更改列或添加新列时更新迁移文件

如何在时间戳上使用“NOW()”更新 Sequelize?

Sequelize:模型未关联到 Model2