nodejs/sequelize/many_to_many_double.js
#!/usr/bin/env node
// https://cirosantilli.com/sequelize-example
const assert = require('assert');
const path = require('path');
const { DataTypes } = require('sequelize');
const common = require('./common')
const sequelize = common.sequelize(__filename, process.argv[2], { define: { timestamps: false } })
;(async () => {
// Create the tables.
const User = sequelize.define('User', {
name: { type: DataTypes.STRING },
}, {});
const Post = sequelize.define('Post', {
body: { type: DataTypes.STRING },
}, {});
User.belongsToMany(Post, {through: 'UserLikesPost', as: 'likedPosts'});
Post.belongsToMany(User, {through: 'UserLikesPost', as: 'likers'});
User.belongsToMany(Post, {through: 'UserFollowsPost', as: 'followedPosts'});
Post.belongsToMany(User, {through: 'UserFollowsPost', as: 'followers'});
await sequelize.sync({force: true});
// Create some users and likes.
const user0 = await User.create({name: 'user0'})
const user1 = await User.create({name: 'user1'})
const user2 = await User.create({name: 'user2'})
const post0 = await Post.create({body: 'post0'});
const post1 = await Post.create({body: 'post1'});
const post2 = await Post.create({body: 'post2'});
// Autogenerated add* methods
// Setup likes and follows.
await user0.addLikedPost(post0)
await post1.addLikers([user0, user2])
await user1.addFollowedPosts([post0, post1])
await post1.addFollower(user2)
// Autogenerated get* methods
// Get likes by a user.
const user0Likes = await user0.getLikedPosts({order: [['body', 'ASC']]})
assert.strictEqual(user0Likes[0].body, 'post0');
assert.strictEqual(user0Likes[1].body, 'post1');
assert.strictEqual(user0Likes.length, 2);
const user1Likes = await user1.getLikedPosts({order: [['body', 'ASC']]})
assert.strictEqual(user1Likes.length, 0);
const user2Likes = await user2.getLikedPosts({order: [['body', 'ASC']]})
assert.strictEqual(user2Likes[0].body, 'post1');
assert.strictEqual(user2Likes.length, 1);
// Get users that liked a given post.
const post0Likers = await post0.getLikers({order: [['name', 'ASC']]})
assert.strictEqual(post0Likers[0].name, 'user0');
assert.strictEqual(post0Likers.length, 1);
const post1Likers = await post1.getLikers({order: [['name', 'ASC']]})
assert.strictEqual(post1Likers[0].name, 'user0');
assert.strictEqual(post1Likers[1].name, 'user2');
assert.strictEqual(post1Likers.length, 2);
const post2Likers = await post2.getLikers({order: [['name', 'ASC']]})
assert.strictEqual(post2Likers.length, 0);
// Get follows by a user.
const user0Follows = await user0.getFollowedPosts({order: [['body', 'ASC']]})
assert.strictEqual(user0Follows.length, 0);
const user1Follows = await user1.getFollowedPosts({order: [['body', 'ASC']]})
assert.strictEqual(user1Follows[0].body, 'post0');
assert.strictEqual(user1Follows[1].body, 'post1');
assert.strictEqual(user1Follows.length, 2);
const user2Follows = await user2.getFollowedPosts({order: [['body', 'ASC']]})
assert.strictEqual(user2Follows[0].body, 'post1');
assert.strictEqual(user2Follows.length, 1);
// Get users that followed a given post.
const post0Followers = await post0.getFollowers({order: [['name', 'ASC']]})
assert.strictEqual(post0Followers[0].name, 'user1');
assert.strictEqual(post0Followers.length, 1);
const post1Followers = await post1.getFollowers({order: [['name', 'ASC']]})
assert.strictEqual(post1Followers[0].name, 'user1');
assert.strictEqual(post1Followers[1].name, 'user2');
assert.strictEqual(post1Followers.length, 2);
const post2Followers = await post2.getFollowers({order: [['name', 'ASC']]})
assert.strictEqual(post2Followers.length, 0);
// Same as getLikedPosts but with the user ID instead of the model object.
// as is mandatory to disambiguate which one we want to get.
{
const user0Likes = await Post.findAll({
include: [{
model: User,
as: 'likers',
where: {id: user0.id},
}],
order: [['body', 'ASC']],
})
assert.strictEqual(user0Likes[0].body, 'post0');
assert.strictEqual(user0Likes[1].body, 'post1');
assert.strictEqual(user0Likes.length, 2);
}
// Alternatively, we can also pass the association object instead of model + as.
// This is actually nicer!
{
const user0Likes = await Post.findAll({
include: [{
association: Post.associations.likers,
where: {id: user0.id},
}],
order: [['body', 'ASC']],
})
assert.strictEqual(user0Likes[0].body, 'post0');
assert.strictEqual(user0Likes[1].body, 'post1');
assert.strictEqual(user0Likes.length, 2);
}
// Yet another way that can be more useful in nested includes.
{
const user0Likes = (await User.findOne({
where: {id: user0.id},
include: [{
model: Post,
as: 'likedPosts',
}],
order: [[{model: Post, as: 'likedPosts'}, 'body', 'ASC']],
})).likedPosts
assert.strictEqual(user0Likes[0].body, 'post0');
assert.strictEqual(user0Likes[1].body, 'post1');
assert.strictEqual(user0Likes.length, 2);
}
})().finally(() => { return sequelize.close() });