fredrikekelund
fredrikekelund

Reputation: 2095

Sequelize associations: set[Models] adds new models instead of associating existing ones

I'm using Sequelize and I'm trying to create associations between two different tables, where x.belongsTo(y) and y.hasMany(x). After having done x.setY(yInstance) and y.getXs() it seems only new rows have been added to x and no associations to my already created instances have been created.

var Promise = require("bluebird"),
    Sequelize = require("sequelize");

var sequelize = new Sequelize("Test", "postgres", "password", {
    host: "localhost",
    dialect: "postgres",
    pool: {
        max: 5,
        min: 0,
        idle: 10000
    }
});
var Schedule = sequelize.define("Schedule", {
    website: {
        type: Sequelize.STRING
    }
});
var SiteConfig = sequelize.define("SiteConfig", {
    systemType: {
        type: Sequelize.STRING
    }
});
var Selector = sequelize.define("Selector", {
    type: {
        type: Sequelize.STRING
    },
    content: {
        type: Sequelize.STRING
    }
});
Selector.belongsTo(SiteConfig);
SiteConfig.hasMany(Selector);

var testSchedule = {
    website: "google.com"
};
var testSiteConfig = {
    systemType: "one"
};
var testSelectors = [
    {type: "foo", content: "foo"},
    {type: "foo", content: "bar"}
];



Promise.all([
    Schedule.sync({force: true}),
    SiteConfig.sync({force: true}),
    Selector.sync({force: true})
]).then(function () {
    return Promise.all([
        Schedule.create(testSchedule),
        SiteConfig.create(testSiteConfig),
        Selector.bulkCreate(testSelectors)
    ]);
}).spread(function (schedule, siteConfig, selectors) {
    return Promise.map(selectors, function (selector) {
        return selector.setSiteConfig(siteConfig);
    }).then(function (array) {
        return siteConfig.getSelectors();
    }).each(function (selector) {
        // This is where I expect "foo" and "bar" but instead get null
        console.log("Selector content:", selector.get("content"));
    });
});

I'd expect this code to add a SiteConfigId column to my Selectors so that my siteConfig.getSelectors() would return my testSelectors. How can I achieve this?

Upvotes: 3

Views: 1144

Answers (1)

Kevin Wu
Kevin Wu

Reputation: 8571

[UPDATE]

It turns out what I had earlier was wrong. The method setSiteConfig() is not what you want to use. I checked the db and it looks like Sequelize created two new records instead of associating the existing foo/bar selectors:

test=# select * from "Selectors";
 id | type | content |         createdAt          |         updatedAt          | SiteConfigId 
----+------+---------+----------------------------+----------------------------+--------------
  1 | foo  | foo     | 2015-04-05 20:38:55.282-07 | 2015-04-05 20:38:55.282-07 |             
  2 | foo  | bar     | 2015-04-05 20:38:55.282-07 | 2015-04-05 20:38:55.282-07 |             
  3 |      |         | 2015-04-05 20:38:55.282-07 | 2015-04-05 20:38:55.311-07 |            1
  4 |      |         | 2015-04-05 20:38:55.282-07 | 2015-04-05 20:38:55.31-07  |            1

So what is different? You can't use setSiteConfig on the child rows, instead you call addSelectors on siteConfig and pass in the selectors you want to associate. See updated code below.

Changed Promise variable to BPromise because node has a native Promise module now which would cause a conflict. Also I believe Sequelize has bluebird built-in so you can also just use Sequelize.Promise.

Removed the nested promise in your spread call because there is no need for it.

Side note: Promise.all returns a single result array so I don't think you should be using .spread().

var BPromise = require("bluebird");
var Sequelize = require("sequelize");

var sequelize = new Sequelize('test', 'root', 'password', {
  host: "localhost",
  dialect: "postgres",
  pool: {
    max: 5,
    min: 0,
    idle: 10000
  }
});

var Schedule = sequelize.define("Schedule", {
  website: {
    type: Sequelize.STRING
  }
});

var SiteConfig = sequelize.define("SiteConfig", {
  systemType: {
    type: Sequelize.STRING
  }
});

var Selector = sequelize.define("Selector", {
  type: {
    type: Sequelize.STRING
  },
  content: {
    type: Sequelize.STRING
  }
});

Selector.belongsTo(SiteConfig);
SiteConfig.hasMany(Selector);

var testSchedule = {
  website: "google.com"
};
var testSiteConfig = {
  systemType: "one"
};
var testSelectors = [
  {type: "foo", content: "foo"},
  {type: "foo", content: "bar"}
];

sequelize.sync({ force: true })
.then(function(result) {
  return BPromise.all([
    Schedule.create(testSchedule),
    SiteConfig.create(testSiteConfig),
    Selector.bulkCreate(testSelectors, { returning: true })
  ]);
})
.then(function(result) {
  var siteConfig = result[1];
  var selectors = result[2];

return siteConfig.addSelectors(selectors);
})
.then(function (result) {
  return this.siteConfig.getSelectors();
})
.each(function(result) {
  console.log('boomshakalaka:', result.get());
})
.catch(function(error) {
  console.log(error);
});

Upvotes: 2

Related Questions