본문 바로가기
프로젝트

유저 정보에 기반한 모임 추천 기능 만들기

by 해룸 2024. 2. 13.
//유저 테이블
model Users {
  id          Int       @id @default(autoincrement()) @map("id")
  email       String    @unique @map("email")
  password    String    @map("password")
  name        String    @map("name")
  interest    String    @map("interest") 
  profileImage String?   @map("profileImage")
  isVerified  Boolean   @default(false) @map("isVerified") 

  postId      Posts[]
  Likes       Likes[]
  CommunityUsers CommunityUsers[]
  followers        Follow[]  @relation("UserFollowers")
  following        Follow[]  @relation("UserFollowing")

  @@map("Users")
}

//커뮤니티 테이블
model Community {
  id              Int         @id @default(autoincrement()) @map("id")
  comName         String      @map("comName")
  interest        String      @map("interest")
  managerId       Int         @map("managerId")
  communityImage  String?     @map("communityImage")
  communityContent String      @map("communityContent")

  posts Posts[]
  communityUsers CommunityUsers[]

  @@map("Community")
}

스키마 파일은 이렇다.

회원가입시에 유저에게 관심사 정보를 받을 수 있고, 커뮤니티를 생성할때도 커뮤니티 관심사를 입력해야 생성이 가능하다.

 

//로그인이 안되어있거나, 관심사를 선택하지 않은 유저의 경우 랜덤으로 커뮤니티 조회하기(첫화면)
router.get('/community', async (req, res, next) => {
	const comId = await prisma.community.findMany({
		select: {
			id: true,
		},
	});

	function Random() {
		const randomId = comId.map((item) => item.id);
		// Fisher-Yates 알고리즘을 사용하여 배열 랜덤 섞기
		for (let i = randomId.length - 1; i > 0; i--) {
			const j = Math.floor(Math.random() * (i + 1));
			// 배열의 원소 위치 바꾸기
			[randomId[i], randomId[j]] = [randomId[j], randomId[i]];
		}
		return randomId;
	}
	const R = Random();

	const selectId = R.slice(0, 7);
	console.log(R, selectId);
	const randomCommunity = await prisma.community.findMany({
		where: { id: { in: selectId } },
		orderBy: { id: 'desc' },
		select: {
			id: true,
			comName: true,
			interest: true,
			communityImage: true,
			//   manageId: true,
		},
	});
	return res.status(200).json({ data: randomCommunity });
});

커뮤니티 아이디 목록을 불러와 그걸 랜덤으로 섞은 배열을 만든다.

그리고 랜덤으로 만들어진 배열에서 slice를 이용해 첫번째부터 여섯번째 모임아이디만 가진 걸 selectId에 할당한다.

selectId 안에 들어있는 커뮤니티 목록만 화면에 배치되도록 코드를 작성했다.

 

router.get('/recommendCom', authMiddleWare, async (req, res, next) => {
	try {
		const userId = req.user.id;

		// ** 관심사가 하나라도 일치하는 모임 출력하기
		// 1. 유저관심사 2. 커뮤니티 관심사 split(",")으로 나눈 배열을 for문 두개로 하나하나 비교하기
		// 일치하는 경우, 일치관심사배열에 넣기
		// 일치관심사 배열로 커뮤니티 조회하기

		//1. 유저의 관심사 모음
		const userInterest = await prisma.users.findMany({
			where: { id: +userId },
			select: {
				interest: true,
			},
		});

		if (!userInterest) {
			return res.status(401).json({ message: '관심사 정보를 추가해주십시오.' });
		}

		//2. 커뮤니티 관심사 모음
		const comInterest = await prisma.community.findMany({
			select: {
				interest: true,
			},
		});

		//관심사 배열
		const removeSpaces = (str) => str.split(' ').join('');
		const userInterArr = removeSpaces(userInterest[0].interest).split(',');
		const comInterArr = comInterest.map((item) =>
			removeSpaces(item.interest).split(','),
		);
		// console.log(userInterArr, comInterArr);
		const correctInter = [];
		for (let i = 0; i < userInterArr.length; i++) {
			for (let j = 0; j < comInterArr.length; j++) {
				for (let k = 0; k < comInterArr[j].length; k++) {
					if (userInterArr[i] === comInterArr[j][k]) {
						correctInter.push(userInterArr[i]);
						break;
					}
				}
			}
		}
		const uniqueCorrectInter = [...new Set(correctInter)];
		// console.log(uniqueCorrectInter);

		//관심사와 일치하는 모임 출력
		const correctCom = await prisma.community.findMany({
			where: {
				OR: uniqueCorrectInter.map((interest) => ({
					interest: {
						contains: interest,
					},
				})),
			},
			select: {
				id: true,
				comName: true,
				interest: true,
				communityImage: true,
			},
		});

		return res.status(200).json({ data: correctCom });
	} catch (err) {
		next(err);
	}
});

유저 관심사 = [게임, 산책, 집꾸미기]

커뮤니티 관심사 = [ [게임], [애완동물, 가드닝], [커비] ]

이렇게 구성되어있다면, for문을 세개로 돌려 유저관심사를 커뮤니티관심사에 각각 대조시킨다.

그리고 일치하는 관심사가 있다면 UniqueCorrectInter 안에 넣어준다.

마지막으로 findMany의 조건을 통해 uniqueCorrectInter.interest 가 하나라도 포함된다면 화면에 출력하도록 한다.

 

이 코드의 한계는 입력해 놓은 관심사가 정확하게 일치해야한다는 점이다.

이걸 해결하기 위해 생각한 방법은 enum으로 이미 만들어놓은 관심사 목록 태그 중에 선택하도록 하는 것인데, 

백엔드 내에서 어떻게 코드를 짜야할지 모르겠어서 해보지는 못했다.

또는 ai를 이용해 비슷한 어휘가 있으면 검색이 가능하도록 하는 방법도 있을텐데 이 방법은 생각만 해보고 시도해보지않았다.