Reputation: 85
I'm trying to build a blog web-application as an excercise to understand ORM and Sequelize in particular. I managed quite easily to form relations between posts and comments and users and posts. No problems there. The horror begins when I try to link users to users as followers and users to users as followeds. I also want it to be possible to follow yourself.
I have tried something like this:
const User = sequelize.define('user', {
firstName: {
type: Sequelize.STRING
},
lastName: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
},
activated: {
type: Sequelize.BOOLEAN
}
})
User.belongsToMany(User, {as: "Follower", foreignKey: "FollowerId", through: "Follower_Followeds"})
User.belongsToMany(User, {as: "Followed", foreignKey: "FollowedId", through: "Follower_Followeds"})
And to set the relations:
app.post("/followhandler", function(req, res) {
let userId = req.session.userId
let followId = req.body.followId
User.findById(userId)
.then( currentUser => {
User.findById(followId)
.then( follows => {
currentUser.addUser(follows)
})
})
.catch(e => console.log(e))
})
But the Follower_Followeds table will simply not get updated. I've also tried to skip the many to many implementation of Sequelize by creating a separate table and adding the relations manually:
const FollowerFollowed = sequelize.define('followerFollowed', {
followedId: {
type: Sequelize.INTEGER
},
followerId: {
type: Sequelize.INTEGER
}
})
//define Users
const User = sequelize.define('user', {
firstName: {
type: Sequelize.STRING
},
lastName: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
},
activated: {
type: Sequelize.BOOLEAN
}
})
And the handler:
app.post("/followhandler", function(req, res) {
let userId = req.session.userId
let followId = req.body.followId
FollowerFollowed.create( {
followerId: userId,
followedId: followId
})
.then( rel => console.log(rel))
.catch(e => console.log(e))
})
But I'm getting the following error in this case:
TypeError: val.replace is not a function at Object.SqlString.escape (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/sql-string.js:61:15) at Object.escape (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/dialects/abstract/query-generator.js:978:22) at Object.insertQuery (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/dialects/abstract/query-generator.js:299:28) at QueryInterface.insert (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/query-interface.js:497:33) at . (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/instance.js:679:56) at tryCatcher (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/util.js:16:23) at Promise._settlePromiseFromHandler (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:510:31) at Promise._settlePromise (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:567:18) at Promise._settlePromise0 (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:612:10) at Promise._settlePromises (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:691:18) at Async._drainQueue (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/async.js:133:16) at Async._drainQueues (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/async.js:143:10) at Immediate.Async.drainQueues (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/async.js:17:14) at runCallback (timers.js:649:20) at tryOnImmediate (timers.js:622:5) at processImmediate [as _immediateCallback] (timers.js:594:5) TypeError: val.replace is not a function at Object.SqlString.escape (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/sql-string.js:61:15) at Object.escape (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/dialects/abstract/query-generator.js:978:22) at Object.insertQuery (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/dialects/abstract/query-generator.js:299:28) at QueryInterface.insert (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/query-interface.js:497:33) at . (/home/piepongwong/Documents/NYCDA/blog/node_modules/sequelize/lib/instance.js:679:56) at tryCatcher (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/util.js:16:23) at Promise._settlePromiseFromHandler (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:510:31) at Promise._settlePromise (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:567:18) at Promise._settlePromise0 (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:612:10) at Promise._settlePromises (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/promise.js:691:18) at Async._drainQueue (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/async.js:133:16) at Async._drainQueues (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/async.js:143:10) at Immediate.Async.drainQueues (/home/piepongwong/Documents/NYCDA/blog/node_modules/bluebird/js/release/async.js:17:14) at runCallback (timers.js:649:20) at tryOnImmediate (timers.js:622:5) at processImmediate [as _immediateCallback] (timers.js:594:5)
Upvotes: 1
Views: 1449
Reputation: 7411
When you create the M:M association you use as: 'Follower'
and as: 'Followed'
attributes. It influences the way you can add/set/delete associations between users. Method to add followed user to other user is now called addFollowed
and would be used in exactly the same way you did it.
User.findById(userId).then( currentUser => {
User.findById(followId).then( follows => {
currentUser.addFollowed(follows); // notice the difference here
});
});
The same occurs if you want to add follower to given user - then you would use addFollower
method.
Moreover, in your second solution you have made a mistake while creating the associating Model. In the User
model you have defined associations via foreign keys FollowerId
and FollowedId
, however in the FollowerFolloweds
definition you have created followerId
and followedId
, so those two do not match each other - you need to keep the names consistent.
EDIT
According to the documentation in the belongsToMany
relation, the as
attribute should be named as plural, so in your case you should name those as: 'Followers'
and as: 'Followeds'
(the second one seems a little strange). Sequelize singularizes those values itself, however you can define it by yourself using object as: { singular: 'Follower', plural: 'Followers' }
The alias of this association. If you provide a string, it should be plural, and will be singularized using node.inflection. If you want to control the singular version yourself, provide an object with plural and singular keys.
Upvotes: 2