[Sequelize] Join (sequelize-typescript)
์ํ๋ผ์ด์ฆ์ ORM ๊ธฐ๋ฅ์ ํตํด join์ ์ํํ๋ ๋ฐฉ๋ฒ์ ์ฒ์ฒํ ๋ค๋ค๋ณด๊ฒ ๋ค.
ORM์ ๋จ์ CRUD ์์
์์ ํน์ถ๋ ์์ฐ์ฑ์ ๋ณด์ด์ง๋ง, ๋จ์ํ ํํ์ Join ๋ํ ์ต์ํ๋ค๋ ์ ์ ํ์์ ๊น๋ํ ์ฝ๋์ ๊ด์ฐฎ์ ์์ฐ์ฑ์ ๋ณด์ฌ์ค๋ค,
์ผ๋จ ์ฌ์ฉ์๋ฅผ ๋ปํ๋ "User" ์ํฐํฐ์

์ฌ์ฉ์๊ฐ ์์ฑํ ๊ฒ์๊ธ์ ๋ํ๋ด๋ "Post" ์ํฐํฐ 2๊ฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ ์คํธ๋ฅผ ํ๋ฒ ํด๋ณด๊ฒ ๋ค.

@BelongsTo ๊ด๊ณ
์ ๊ธฐ์ ๋ง์ฝ ๊ฒ์๊ธ์ ๊ฐ์ ธ์ค๋, ๊ทธ ๊ฒ์๊ธ์ ์์ฑํ ์ฌ์ฉ์๊น์ง ํจ๊ป ๊ฐ์ ธ์ค๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น?
๊ด๊ณ์ ์ผ๋ก ์๊ฐํ๋ฉด ์ฌ์ฉ์๊ฐ ๊ฒ์๊ธ์ ์์ฑํ์ผ๋ ๊ฒ์๊ธ์ ์ฌ์ฉ์์๊ฒ ์ํด์๋ค๊ณ ํ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ ๊ฒ์๊ธ์ ์์ฑํ ์ฌ์ฉ์์ ๊ณ ์ ํค๋ฅผ ์ปฌ๋ผ์ผ๋ก ๋ณด์ ํ๋ ๊ฒ์ผ๋ก ๊ทธ ์์์ฑ์ ์ฆ๋ช
ํ๋ค.
์ด๋ฐ ๊ฒฝ์ฐ์๋ BelongsTo ๊ด๊ณ๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
์ธ๋ํค ์ปฌ๋ผ์ ForeignKey ๋ฐ์ฝ๋ ์ดํฐ๋ก ํด๋น ์ฌ์ฉ์ ๋ชจ๋ธ์ ์ฐธ์กฐํ๋ ํค์์ ๋ช
์ํด์ค๋ค.
ํด๋น ๋ชจ๋ธ์ ๋ฐํํ๋ ํด๋ก์ ๋ฅผ ๋๊ฒจ์ฃผ๋ฉด ๋๋ค.

๊ทธ๋ฆฌ๊ณ ์ปฌ๋ผ์ด ์๋ BelongsTo ํ๋๋ก ์กฐ์ธํด์จ ๊ฐ์ ๋ด์๋ ํ๋๋ฅผ ์ง์ ํด์ค๋ค.
BelongsTo์๋ ์ฌ์ฉ์ ๋ชจ๋ธ์ ๋ฃ์ด์ฃผ๊ณ , ํ๋์ ํ์
์ ๋ชจ๋ธํ์
์ด๋ ๊ทธ๊ฑฐ๋ ๋งคํ๋๋ ๊ฐ์ฒด ํ์
์ ์๋ฌด๊ฑฐ๋ ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.

๊ทธ๋ผ ์ด์ ์ด๋ฐ์์ผ๋ก Join ์ํ์ด ๊ฐ๋ฅํด์ง๋ค.
join์ ๊ธฐ๋ณธ์ ์ผ๋ก find ๋ฉ์๋๋ค์ include ์ต์
์ ํตํด ์ํํ๋๋ฐ, model์ User๋ฅผ ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.

๊ทธ๋ผ ์๋์ ๊ฐ์ด ์ฟผ๋ฆฌ๊ฐ ๋ฝํ์ ์คํ๋ ๊ฒ์ด๋ค.

๋ณด๊ธฐ ํ๋๋ ์ ๋ ฌํด์ ๋ณด์
select
"Post"."id",
"Post"."userId",
"Post"."title",
"Post"."content",
"Post"."useYn",
"Post"."createdAt",
"Post"."updatedAt",
"user"."id" as "user.id",
"user"."email" as "user.email",
"user"."password" as "user.password",
"user"."passwordSalt" as "user.passwordSalt",
"user"."name" as "user.name",
"user"."userType" as "user.userType",
"user"."userStatus" as "user.userStatus",
"user"."createdAt" as "user.createdAt",
"user"."updatedAt" as "user.updatedAt"
from
"Posts" as "Post"
left outer join "Users" as "user" on
"Post"."userId" = "user"."id"
where
"Post"."useYn" = true;
left ์กฐ์ธ์ User์ ๊ณ ์ ํค๋ก ์กฐ๊ฑด์ ๊ฑธ์ด์ ์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.

๋ด๋ถ&์ธ๋ถ์กฐ์ธ ์ค์
์์ BelongsTo๋ก ๋๋ฆฐ ์ฟผ๋ฆฌ์ ๊ฒฝ์ฐ์๋ ๊ธฐ๋ณธ์ ์ผ๋ก Left ์ธ๋ถ์กฐ์ธ์ ์ํํ๋ค.
ํ์ง๋ง ๋ด๋ถ์กฐ์ธ์ผ๋ก ๋๋ฆฌ๊ณ ์ถ์ ์๋ ์์ง ์๊ฒ ๋๊ฐ?
์ด๋ฐ ๊ฒฝ์ฐ์๋ required ์ต์
๊ฐ์ true๋ก ์ฃผ๋ฉด ๋ด๋ถ์กฐ์ธ์ ์ํํ๋ค.
๋ฐ๋๋ก false๋ฅผ ์ฃผ๋ฉด ์ธ๋ถ์กฐ์ธ์ ์ํํ๋ค.

select
"Post"."id",
"Post"."userId",
"Post"."title",
"Post"."content",
"Post"."useYn",
"Post"."createdAt",
"Post"."updatedAt",
"user"."id" as "user.id",
"user"."email" as "user.email",
"user"."password" as "user.password",
"user"."passwordSalt" as "user.passwordSalt",
"user"."name" as "user.name",
"user"."userType" as "user.userType",
"user"."userStatus" as "user.userStatus",
"user"."createdAt" as "user.createdAt",
"user"."updatedAt" as "user.updatedAt"
from
"Posts" as "Post"
inner join "Users" as "user" on
"Post"."userId" = "user"."id"
where
"Post"."useYn" = true
order by
"Post"."createdAt" desc
limit 10 offset 0;On ์ ์ค์
join๋ฌธ์ on ์ ์ ์ถ๊ฐ ์กฐ๊ฑด์ ์ ์ถ๊ฐํ๊ณ ์ถ๋ค๋ฉด where ์ต์
๊ฐ์ ์ฌ์ฉํ๋ค.
๊ทธ๋ฌ๋ฉด ๊ธฐ๋ณธ on ์ ์ ๋ํด์ ์กฐ๊ฑด์ ๋ํด์ค ๊ฒ์ด๋ค.

์ด๋ ๊ฒ
select
"Post"."id",
"Post"."userId",
"Post"."title",
"Post"."content",
"Post"."useYn",
"Post"."createdAt",
"Post"."updatedAt",
"user"."id" as "user.id",
"user"."email" as "user.email",
"user"."password" as "user.password",
"user"."passwordSalt" as "user.passwordSalt",
"user"."name" as "user.name",
"user"."userType" as "user.userType",
"user"."userStatus" as "user.userStatus",
"user"."createdAt" as "user.createdAt",
"user"."updatedAt" as "user.updatedAt"
from
"Posts" as "Post"
inner join "Users" as "user" on
"Post"."userId" = "user"."id"
and "user"."userStatus" = 0
where
"Post"."useYn" = true
order by
"Post"."createdAt" desc
limit 10 offset 0;
๊ทธ๋ฐ๋ฐ ์ ๋ฐ ์๋ ๋งคํ์ด ์ง๊ฒจ์์ ธ์ join ์กฐ๊ฑด์ ์ง์ ๋ค ์ง์ ํ๊ณ ์ถ์ ์๋ ์๋ค.
๊ทธ๋ด ๋๋ on ์ต์
์ผ๋ก ์กฐ๊ฑด์ ์ง์ ํ๋ฉด ๋๋ค.
์ด๊ฑธ ์ฐ๋ฉด ์๋์ผ๋ก ์์ฑ๋๋ on ์ ์ด ์ ๊ฑฐ๋๊ณ ์ฐ๋ฆฌ๊ฐ ๋ฃ์ ๊ฒ๋ง ์กฐ๊ฑด์ผ๋ก ๋ค์ด๊ฐ๋ค.

select
"Post"."id",
"Post"."userId",
"Post"."title",
"Post"."content",
"Post"."useYn",
"Post"."createdAt",
"Post"."updatedAt",
"user"."id" as "user.id",
"user"."email" as "user.email",
"user"."password" as "user.password",
"user"."passwordSalt" as "user.passwordSalt",
"user"."name" as "user.name",
"user"."userType" as "user.userType",
"user"."userStatus" as "user.userStatus",
"user"."createdAt" as "user.createdAt",
"user"."updatedAt" as "user.updatedAt"
from
"Posts" as "Post"
left outer join "Users" as "user" on
"user"."id" = "Post"."userId"
and "user"."userStatus" = 0
where
"Post"."useYn" = true
order by
"Post"."createdAt" desc
limit 10 offset 0;Join ์ค์ฒฉ
๋ค๋ฅธ ํ
์ด๋ธ์ ํ๋ฒ ์กฐ์ธํ๋๋ฐ, ์กฐ์ธํ ํ
์ด๋ธ์์ ๋ ์กฐ์ธ์ ํด์ค๊ณ ์ถ์ ์ ์๋ค.
๊ทธ๋ด ๋๋ ํด๋น include ์ ์ ๋ include๋ฅผ ์ฌ๊ท์ ์ผ๋ก ์ ์ํ๋ฉด ๋๋ค.

HasOne ๊ด๊ณ
์ด๋ฒ์ ์ฌ์ฉ์์ ๊ด์ ์ผ๋ก ๋์๊ฐ๋ณด์.
์ผ๋ฐ์ ์ด์ง๋ ์์ง๋ง, ์ฌ์ฉ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํด์ ์ฌ์ฉ์๊ฐ ์์ ํ ํ๋์ ๊ฒ์๊ธ์ ๊ฐ์ ธ์ค๋ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํด๋ณด๊ฒ ๋ค.
๊ฒ์๊ธ์ ์ฌ์ฉ์๊ฐ ์์ฑํ ๊ฒ์ด๊ณ ์ฌ์ฉ์์๊ฒ ์ํด์์ผ๋, ์ฌ์ฉ์๋ ๊ฒ์๊ธ์ ๊ฐ์ง๊ณ ์๋ค๊ณ ๋ณผ ์ ์๋ค.
ํ์ฌ ์ค์ฌ์ด ๋ ์ฌ์ฉ์๋ ๊ฒ์๊ธ์ ๋ํ ์ฐธ์กฐ์์ฑ์ ๊ฐ์ง๊ณ ์์ง๋ ์์ง๋ง, ์ํด์๋ ๊ฒ์๊ธ ์ํฐํฐ Post๊ฐ ์ฐธ์กฐ์์ฑ์ ๊ฐ๊ณ ์๊ธฐ์ ์ฑ๋ฆฝํ ์ ์๋ ๊ด๊ณ๋ค.
์ด๋ฒ์ ์ด๊ฑธ ์ด์ฉํด์ ์ฌ์ฉ์ ์กฐํ์์ ๊ฒ์๊ธ๋ ํ๋ ๊ฐ์ ธ์ค๋๋ก ํด๋ณด๊ฒ ๋ค.
๋ค์๊ณผ ๊ฐ์ด ๊ด๊ณ๋ฅผ ๋ช
์ํด์ฃผ๊ณ

include๋ง ๋๋ฐ๋ก ์จ์ฃผ๋ฉด ๋๋ค.

๊ทธ๋ผ ์๋์ ๊ฐ์ด ์ฟผ๋ฆฌ๊ฐ ๋ฝํ์
select
"User"."id",
"User"."email",
"User"."password",
"User"."passwordSalt",
"User"."name",
"User"."userType",
"User"."userStatus",
"User"."createdAt",
"User"."updatedAt",
"post"."id" as "post.id",
"post"."userId" as "post.userId",
"post"."title" as "post.title",
"post"."content" as "post.content",
"post"."useYn" as "post.useYn",
"post"."createdAt" as "post.createdAt",
"post"."updatedAt" as "post.updatedAt"
from
"Users" as "User"
left outer join "Posts" as "post" on
"User"."id" = "post"."userId"
where
"User"."id" = 1
and "User"."userStatus" = 0;
์์๊ฒ ์ ์ถ๋ ฅ๋ ๊ฒ์ด๋ค.

HasMany ๊ด๊ณ
์ฌ์ฉ์์ ๊ด์ ์์, ์ฌ์ฉ์๋ ์๋ง ์ฌ๋ฌ๊ฐ์ ๊ฒ์๊ธ์ ์ธ ์ ์์ ๊ฒ์ด๋ค.
๋ฐ๋ผ์ ์ฌ์ฉ์๋ ์ฌ๋ฌ๊ฐ์ ๊ฒ์๊ธ์ ์์ ํ๊ณ ์๋ค๊ณ ํ ์ ์๋ค.
HasOne์์ ๊ทธ๋๋ก ๋ณต์ํ๋ง ๋ ๊ฐ๋
์ด๋ค.
์ด๋ฒ์๋ ์ฌ์ฉ์๋ฅผ ๊ฐ์ ธ์ด๊ณผ ๋์์ ์ฌ์ฉ์๊ฐ ๊ฐ๊ณ ์๋ ๊ฒ์๊ธ์ ์ ๋ถ ๊ฐ์ ธ์ฌ ์ ์๋๋ก ํด๋ณด๊ฒ ๋ค.
HasMany๋ก ๋ฌ๊ณ , ํ๋์ ํ์
์ ๋ฐฐ์ด๋ก ์ค์ ํ๋ค.

๊ทธ๋ฆฌ๊ณ ์ด์ ๊ณผ ๋์ผํ๊ฒ findOne ์ฝ๋๋ฅผ ์์ฑํ๋ค.

๊ทธ๋ผ ๋ค์๊ณผ ๊ฐ์ด ์ฟผ๋ฆฌ๊ฐ ๋ฝํ ๊ฒ์ด๊ณ
select
"User"."id",
"User"."email",
"User"."password",
"User"."passwordSalt",
"User"."name",
"User"."userType",
"User"."userStatus",
"User"."createdAt",
"User"."updatedAt",
"posts"."id" as "posts.id",
"posts"."userId" as "posts.userId",
"posts"."title" as "posts.title",
"posts"."content" as "posts.content",
"posts"."useYn" as "posts.useYn",
"posts"."createdAt" as "posts.createdAt",
"posts"."updatedAt" as "posts.updatedAt"
from
"Users" as "User"
left outer join "Posts" as "posts" on
"User"."id" = "posts"."userId"
where
"User"."id" = 1
and "User"."userStatus" = 0;
์ด๋ ๊ฒ ์๋ํ๋๋ก ์ ๋์ฌ ๊ฒ์ด๋ค.

๋์ผ ์ํฐํฐ ์ธ๋ํค๊ฐ ์ฌ๋ฌ๊ฐ์ผ ๊ฒฝ์ฐ
์ฌ์ฉ์๊ฐ ๋ค๋ฅธ ์ฌ์ฉ์๋ฅผ ์ ๊ณ ํ ๊ฒฝ์ฐ์ ๋ฐ์ดํฐ ๊ด๋ฆฌ๋ฅผ ์๊ฐํด๋ณด์.
๊ทธ๋ผ ๋์ถฉ ๋ค์๊ณผ ๊ฐ์ด ์ ๊ณ ํ ์ฌ๋๊ณผ, ์ ๊ณ ๋นํ ์ฌ๋์ ์๋ณ์๋ฅผ ๊ฐ๊ฒ ๋ ๊ฒ์ด๋ค.
์ํฐํฐ ์ ์์ ์ฌ์ฉ์ ๋จ์ํ๊ฒ ์๊ฐํ๋ค๋ฉด ์ด๋ฐ์์ผ๋ก ํด๋ณผ ์ ์์ ๊ฒ์ด๋ค.


๊ทธ๋ผ ์๋ฌ๊ฐ ๋๋ค.
sendUser์ targetUser๋ฅผ ์ด๋ค ํค๋ก ์กฐ์ธํ๊ณ , alias๋ฅผ ์ด๋ป๊ฒ ํ ์ง ์์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ด๋ค.

์ด๋ด ๋๋ ๋งคํ๋๋ ๊ด๊ณ ๋ฐ์ฝ๋ ์ดํฐ์ ์ฐธ์กฐํ๋ ์ธ๋ํค์ ํ ์ด๋ธ alias๋ฅผ ์ต์ ์ผ๋ก ์ค์ผ ํ๋ค.

๊ทธ๋ฆฌ๊ณ findํ ๋๋ ์ง์ ํ as๋ฅผ ๋ง์ถฐ์ฃผ๋ฉด ๋์ด๋ค.

๊ทธ๋ผ ์ฟผ๋ฆฌ๊ฐ ์ด๋ ๊ฒ ๋ฝํ์
SELECT
"Report"."id",
"Report"."sendUserId",
"Report"."targetUserId",
"Report"."reason",
"Report"."createdAt",
"Report"."updatedAt",
"sendUser"."id" AS "sendUser.id",
"sendUser"."email" AS "sendUser.email",
"sendUser"."password" AS "sendUser.password",
"sendUser"."passwordSalt" AS "sendUser.passwordSalt",
"sendUser"."name" AS "sendUser.name",
"sendUser"."userType" AS "sendUser.userType",
"sendUser"."userStatus" AS "sendUser.userStatus",
"sendUser"."createdAt" AS "sendUser.createdAt",
"sendUser"."updatedAt" AS "sendUser.updatedAt",
"targetUser"."id" AS "targetUser.id",
"targetUser"."email" AS "targetUser.email",
"targetUser"."password" AS "targetUser.password",
"targetUser"."passwordSalt" AS "targetUser.passwordSalt",
"targetUser"."name" AS "targetUser.name",
"targetUser"."userType" AS "targetUser.userType",
"targetUser"."userStatus" AS "targetUser.userStatus",
"targetUser"."createdAt" AS "targetUser.createdAt",
"targetUser"."updatedAt" AS "targetUser.updatedAt"
FROM
"Reports" AS "Report"
LEFT OUTER JOIN "Users" AS "sendUser" ON
"Report"."sendUserId" = "sendUser"."id"
LEFT OUTER JOIN "Users" AS "targetUser" ON
"Report"."targetUserId" = "targetUser"."id";
์ ๊ฐ์ ธ์ฌ ๊ฒ์ด๋ค.

BelongsToMany ๊ด๊ณ: ๋ค๋๋ค ๊ด๊ณ ๋งคํ
์ฌ๊ธฐ์๋ ์กฐ๊ธ ์ด๋ ต๊ฒ ๋๋ ์๋ ์๋ค.
์ผ๋ฐ์ ์ธ ์ผํ๋ชฐ์ ๊ตฌ์กฐ๋ฅผ ๊ณ ๋ คํด๋ณธ๋ค๋ฉด, ์ฌ์ฉ์์ ์ํ์ด๋ผ๋ ๊ฐ์ฅ ์ค์ฌ ๋ชจ๋ธ์ด ์กด์ฌํ ๊ฒ์ด๋ค.
์ฌ์ฉ์๊ฐ ์ํ์ ๊ตฌ๋งคํ๋ฉด ๋ญ๊ฐ ๊ด๊ณ๋ฅผ ํตํด์ ์ฐ๊ฒฐํด์ผ ํ์ง๋ง, ์ฌ์ฉ์๋ ์ํ์๊ฒ ์ข
์์ ์ด์ง ์๊ณ ์ํ๋ ์ฌ์ฉ์์๊ฒ ์ข
์์ ์ด์ง ์๋ค.
ํ ์ํ๋ ์ฌ๋ฌ๋ช
์ ์ฌ์ฉ์์๊ฒ ๊ตฌ๋งค๋ ์ ์๊ณ , ํ ์ฌ์ฉ์๋ ์ฌ๋ฌ๊ฐ์ ์ํ์ ๊ตฌ๋งคํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๊ทธ๋์ ์ด๋ฌํ ๋ค๋๋ค ๊ด๊ณ๋ฅผ ๋งคํํ ๋๋ "UserProduct" ๊ฐ์ ๊ด๊ณ์ฉ ๋งคํ ํ ์ด๋ธ์ ๋ง๋ค์ด์ ์ฌ์ฉ์์ ์ํ์ ๊ณ ์ ํค๋ฅผ ์ฎ์ด ์ฌ์ฉํ๊ณค ํ๋ค.
ํ๋ฒ ์จ๋ณด์.
User์ ๋ํด Product ์ํฐํฐ๋ฅผ ์ถ๊ฐ๋ก ์ ์ํ๊ณ

๋งคํ์ฉ ํ
์ด๋ธ์ ์ ์ํ๋ค.
๊ฐ ํ
์ด๋ธ์ ์ธ๋ํค๋ฅผ ๊ฐ์ง๋๋ก ํ๋ค.

๊ทธ๋ผ ์ด์ ์ฌ์ฉ์๋ฅผ ๊ธฐ์ค์ผ๋ก ํด์ ๊ตฌ๋งคํ ์ํ์ ๊ฐ์ ธ์ค๋ ์ฟผ๋ฆฌ๋ฅผ ๋๋ ค๋ณด๊ฒ ๋ค.
BelongsToMany๋ก Product๋ฅผ ๋ฐํํ๋ ํด๋ก์ , ๋งคํ ํ
์ด๋ธ์ ๋ฐํํ๋ ํด๋ก์ ๋ฅผ ์ ๋ฌํ๋ค.

๊ทธ๋ผ ์ด๋ ๊ฒ ๋จ์ํ๊ฒ ๊ฐ์ ธ์ฌ ์ ์๋ค.

์ฟผ๋ฆฌ๋ ์ด๋ ๊ฒ ๋ฝํ๊ณ
select
"User"."id",
"User"."email",
"User"."password",
"User"."passwordSalt",
"User"."name",
"User"."userType",
"User"."userStatus",
"User"."createdAt",
"User"."updatedAt",
"products"."id" as "products.id",
"products"."name" as "products.name",
"products"."price" as "products.price",
"products"."createdAt" as "products.createdAt",
"products"."updatedAt" as "products.updatedAt",
"products->UserProduct"."id" as "products.UserProduct.id",
"products->UserProduct"."userId" as "products.UserProduct.userId",
"products->UserProduct"."productId" as "products.UserProduct.productId",
"products->UserProduct"."createdAt" as "products.UserProduct.createdAt",
"products->UserProduct"."updatedAt" as "products.UserProduct.updatedAt"
from
"Users" as "User"
left outer join ( "UserProducts" as "products->UserProduct"
inner join "Products" as "products" on
"products"."id" = "products->UserProduct"."productId") on
"User"."id" = "products->UserProduct"."userId";
๊ฐ์ ธ์ค๊ธฐ๋ ์ ๊ฐ์ ธ์ฌ ๊ฒ์ด๋ค.

์ํ์ ๊ธฐ์ค์ผ๋ก ํ ๋๋ ๋ง์ฐฌ๊ฐ์ง๋ค.
๋ฐ๋๋ก๋ง ํด์ฃผ๋ฉด ๋๋ค.


๊ทธ๋ผ ์ด๋ ๊ฒ ์ ๊ฐ์ ธ์ฌ ๊ฒ์ด๋ค.
select
"Product"."id",
"Product"."name",
"Product"."price",
"Product"."createdAt",
"Product"."updatedAt",
"users"."id" as "users.id",
"users"."email" as "users.email",
"users"."password" as "users.password",
"users"."passwordSalt" as "users.passwordSalt",
"users"."name" as "users.name",
"users"."userType" as "users.userType",
"users"."userStatus" as "users.userStatus",
"users"."createdAt" as "users.createdAt",
"users"."updatedAt" as "users.updatedAt",
"users->UserProduct"."id" as "users.UserProduct.id",
"users->UserProduct"."userId" as "users.UserProduct.userId",
"users->UserProduct"."productId" as "users.UserProduct.productId",
"users->UserProduct"."createdAt" as "users.UserProduct.createdAt",
"users->UserProduct"."updatedAt" as "users.UserProduct.updatedAt"
from
"Products" as "Product"
left outer join ( "UserProducts" as "users->UserProduct"
inner join "Users" as "users" on
"users"."id" = "users->UserProduct"."userId") on
"Product"."id" = "users->UserProduct"."productId";

๊ทธ๋ ๋ค.
์ฐธ์กฐ
https://sequelize.org/master/manual/eager-loading.html
https://gist.github.com/zcaceres/83b554ee08726a734088d90d455bc566
https://velog.io/@cadenzah/sequelize-document-4