如何在Sequelize(Node js)中关联对象?

时间:2016-10-04 15:07:36

标签: javascript node.js postgresql sequelize.js

我在Sequlize中有User和File模型。用户可以拥有多个文件。 我有协会 db.User.hasMany(db.File,{as:' Files',foreignKey:' userId',constraints:false});

我想用几个文件初始化User对象并将其保存到数据库。

我写了下一段代码:

 var files = [];

        var file1 = models.File.build();
        file1.name = "JPEG";

        file1.save().then(function () {

        });

        files.push(file1);

        var file2 = models.File.build();
        file2.name = "PNG";

        file2.save().then(function () {

        });

        files.push(file2);


 var newUser = models.User.build();
       newUser.email = email;
 newUser.save().then(function (usr) {

 files.forEach(function (item) {
     newUser.addFile(item);
});

});

但我发现了一个错误,有时几个文件与用户无关。

我发现(在nodejs日志中)命令(更新)用于设置这些文件的外键。 但命令没有执行。几个文件的外键(userId)是空的。

我认为问题出在异步查询中。 如何组织代码结构以避免这个错误?

1 个答案:

答案 0 :(得分:2)

问题正是您所想的,即异步代码。

您需要移动回调中的函数,否则代码会在创建文件之前运行。

JavaScript在进入下一行之前不会等待,所以无论是否完成,它都会运行下一行。搬家之前没有等待的感觉。

所以你基本上添加了一些尚不存在的东西,因为它不会等待文件被保存,然后再继续。

这可以工作,只需移动then回调中的代码:

var files = [];

var file1 = models.File.build();
file1.name = "JPEG";

file1.save().then(function () {
    files.push(file1);

    var file2 = models.File.build();
    file2.name = "PNG";

    file2.save().then(function () {
        files.push(file2);

        var newUser = models.User.build();
        newUser.email = email;
        newUser.save().then(function (usr) {
            files.forEach(function (item) {
                newUser.addFile(item);
            });
        });
    });
});

但那太乱了。相反,你可以链接这样的承诺:

var files = [];

var file1 = models.File.build();
file1.name = "JPEG";

file1.save()
  .then(function(file1) {
      files.push(file1);

      var file2 = models.File.build();
      file2.name = "PNG";

      return file2.save();
  })
  .then(function(file2) {
      files.push(file2);

      var newUser = models.User.build();
      newUser.email = email;

      return newUser.save();
  })
  .then(function(newUser) {
       files.forEach(function(item) {
           newUser.addFile(item);
       });
  });

现在它有点干净,但仍然有点混乱,也有点令人困惑。所以你可以使用生成器函数,如下所示:

var co = require('co');

co(function*() {
    var files = [];

    var file1 = models.File.build();
    file1.name = "JPEG";

    yield file1.save();
    files.push(file1);

    var file2 = models.File.build();
    file2.name = "PNG";

    yield file2.save();
    files.push(file2);

    var newUser = models.User.build();
    newUser.email = email;
    newUser.save();

    files.forEach(function(item) {
        newUser.addFile(item);
    });
});

现在好多了。

仔细观察,你会看到发生了什么。 co接受生成器函数,该函数基本上是带星号*的常规函数​​。这是一个特殊的函数,它增加了yield表达式支持。

yield表达式基本上等待then()回调在继续之前被调用,如果then回调有一个参数,那么它也将返回它。

所以你可以这样做:

var gif = yield models.File.create({
  name: 'gif'
});

而不是:

models.File.create({
  name: 'gif'
}).then(function(gif) {

});

您必须使用名为co的小型节点模块才能实现npm install --save co