피드관리 - Part 1 피드작성 (1) 해시태그 입력

Project Diary/React + MariaDB (PicShare WebApp)

사용자는 입력 필드에서 해시태그를 입력할 수 있으며, 이를 추가하거나 삭제할 수 있습니다. 해시태그는 서버로 전송되어 데이터베이스에 저장됩니다.


데이터베이스

 

  • posts 테이블 : 사용자의 게시물 정보를 저장합니다.
  • hashtags 테이블 : 해시태그 정보를 저장합니다.
  • post_hashtags 테이블 : 게시물과 해시태그 간의 다대다 관계를 관리합니다.

설계 이유

  1. 효율적인 검색
    - 해시태그를 통한 검색 : 해시태그를 인덱싱함으로써 빠른 검색이 가능해집니다.
  2. 다대다 관계 관리(정규화)
    - 게시물과 해시태그의 다대다 관계 : 한 게시물에 여러 해시태그가 붙을 수 있고, 한 해시태그가 여러 게시물에 사용될 수 있습니다. 이를 관리하기 위해 post_hashtags 테이블을 사용하여 다대다 관계를 구현합니다.  
  3. 데이터 무결성
    - 외래 키 제약 조건 : 게시물이나 해시태그가 삭제되면 관련된 post_hashtags 항목도 자동으로 삭제됩니다.
  4. 해시태그 중복 방지
    - 해시태그가 이미 존재하는지 확인한 후 존재하지 않으면 새로 추가합니다.

> 외래 키 제약 조건

CONSTRAINT `post_hashtags_ibfk_1` FOREIGN KEY (`postId`) REFERENCES `posts` (`postId`) ON DELETE CASCADE,
CONSTRAINT `post_hashtags_ibfk_2` FOREIGN KEY (`hashtagId`) REFERENCES `hashtags` (`hashtagId`) ON DELETE CASCADE
  • ON DELETE CASCADE : 부모 테이블의 행이 삭제되면 관련된 자식 테이블의 행도 자동으로 삭제됩니다.
  • ON UPDATE CASCADE : 부모 테이블의 기본 키가 변경되면 관련된 자식 테이블의 외래 키도 자동으로 업데이트됩니다.

 

프론트엔드

 

1. 해시태그 입력 기능

 

1-1 해시태그 변경 핸들러

// 해시태그 변경 핸들러
const handleHashtagChange = (index, value) => {
  const newHashtags = [...hashtags];  // 기존 해시태그 배열 복사
  newHashtags[index] = value;         // 해당 인덱스의 해시태그 변경
  setHashtags(newHashtags);           // 변경된 해시태그 배열로 상태 업데이트
};

 

1-2 해시태그 입력 필드

<div className="hashtags">
  {hashtags.map((hashtag, idx) => (
    <div className="hashtag" key={idx}>
      <span>#</span>
      <input
        type="text"
        placeholder={`${idx + 1}번째 해시태그를 입력하세요`}
        value={hashtag}
        onChange={(e) => handleHashtagChange(idx, e.target.value)}
      />
      {idx === hashtags.length - 1 && (
        <>
          <button type="button" onClick={handleAddHashtag}>
            +
          </button>
          {hashtags.length > 1 && (
            <button type="button" onClick={() => handleRemoveHashtag(idx)}>
              -
            </button>
          )}
        </>
      )}
    </div>
  ))}
</div>
  • handleAddHashtag : 새로운 해시태그 입력 필드를 추가합니다.
  • handleRemoveHashtag : 기존 해시태그 입력 필드를 삭제합니다.

1-3 해시태그 데이터 전송

서버로 전송하기 전에 해시태그 배열을 문자열로 변환하여 formData에 추가합니다.

formData.append("hashtags", hashtags.join(" "));
  • formData.append("hashtags", hashtags.join(" "));

 

백엔드

 

1. 해시태그 저장 처리

// 해시태그 저장
const hashtagArray = hashtags
  .split(" ")
  .map((tag) => (tag.startsWith("#") ? tag : `#${tag}`));

const hashtagInsert = hashtagArray.map((tag) => {
  return new Promise((hashtagres, hashtagdata) => {
    db.query(
      `SELECT hashtagId FROM hashtags WHERE tag = ?`,
      [tag],
      (err, rows) => {
        if (err) {
          console.error("hashtag 검색 중 오류:", err);
          return hashtagdata(err);
        }

        if (rows.length > 0) {
          // 이미 존재하는 해시태그인 경우
          const hashtagId = rows[0].hashtagId;
          db.query(
            `INSERT INTO post_hashtags (postId, hashtagId) VALUES (?, ?)`,
            [postId, hashtagId],
            (err, result) => {
              if (err) {
                console.error("post_hashtags에 삽입 중 오류:", err);
                return hashtagdata(err);
              }
              hashtagres(result);
            }
          );
        } else {
          // 새로운 해시태그인 경우
          db.query(
            `INSERT INTO hashtags (tag) VALUES (?)`,
            [tag],
            (err, result) => {
              if (err) {
                console.error("hashtag 삽입 중 오류:", err);
                return hashtagdata(err);
              }
              const hashtagId = result.insertId;
              db.query(
                `INSERT INTO post_hashtags (postId, hashtagId) VALUES (?, ?)`,
                [postId, hashtagId],
                (err, result) => {
                  if (err) {
                    console.error("post_hashtags에 삽입 중 오류:", err);
                    return hashtagdata(err);
                  }
                  hashtagres(result);
                }
              );
            }
          );
        }
      }
    );
  });
});

새로운 해시태그는 hashtags 테이블에 삽입되고, 기존 해시태그는 post_hashtags 테이블에 postId와 함께 저장됩니다.

 

sql 쿼리문
SELECT hashtagId FROM hashtags WHERE tag = ?
  • 해시태그 테이블에서 태그가 존재하는지 확인합니다.
INSERT INTO post_hashtags (postId, hashtagId) VALUES (?, ?)
  • 이미 존재하는 해시태그의 경우, 해당 해시태그와 게시물의 관계를 post_hashtags 테이블에 저장합니다.
INSERT INTO hashtags (tag) VALUES (?)
  • 새로운 해시태그인 경우, hashtags 테이블에 태그를 삽입합니다.
INSERT INTO post_hashtags (postId, hashtagId) VALUES (?, ?)
  • 새로운 해시태그를 hashtags 테이블에 삽입한 후, 해당 해시태그와 게시물의 관계를 post_hashtags 테이블에 저장합니다.

예시

가정 #sunny -> 이미 'hashtags' 테이블에 존재
#beach -> 새로운 해시태그
결과 1. #sunny의 hashtagId를 가져와 post_hashtags 테이블에 저장
2. # beach 는 hashtags 테이블에 삽입한 후, post_hashtags 테이블에 postId와 함께 저장