[mongoDB] 데이터의 특정 값 자동 증가 구현하기(ft. mongoose, Nodejs)

박기영·2022년 10월 4일
0

DB

목록 보기
1/2

mongoDB로 데이터를 생성하면 _id라는 key와 value가 데이터에 자동적으로 생성된다.
이는 데이터 고유의 번호로 생각된다. 그대로 사용하면 보안상 문제가 있을 것 같다...
보통, 일련의 데이터를 map() 등의 메서드로 나열할 때가 많은데,
map()은 key값을 필요로 한다. 인덱스로 번호로 이를 대체하는 것은 좋지않으므로,
인위적으로 id라는 key를 데이터에 만들어줄 필요가 있다.
문제는, 데이터를 생성할 때마다 일일이 id를 1씩 증가시킬 수는 없다는 것이다.
어떻게 이를 자동적으로 증가하게 만들 수 있을까?

우선, 필자가 구글링을 해본 결과 꽤나 공통적으로 나오는 코드들이 있었는데,
약간 다르게 진행했으므로 이는 참고 자료에만 남겨놓도록 하겠다.

필자만의 생각으로 작성된 코드이기 때문에 정답도 아니고, 효율성도 알 수 없다.
간단하게 백을 구현해야하는 분들은 참고하셔도 좋을 것 같지만...

문제 상황

필자는 강의를 보여주고, 유저들이 거기에 댓글을 달거나 질문 게시판에 질문을 올리는 등의
활동을 할 수 있는 프로젝트를 진행 중이다.
이를 위해서 데이터 모델을 여러개 만들었다.

유저의 정보를 담는 모델, 유저들의 게시물 정보를 담는 모델, 강의 정보를 담는 모델
이렇게 3가지다.

예시로 살펴볼 것은 유저의 정보를 담는 모델이다.
예를들어, 회원가입을 하면 유저의 정보가 DB에 추가될 것이다.
이 때, 데이터의 id 값은 개발자쪽에서 만들어줘야지 이걸 유저가 일일이 값을 입력하게 해서는 안된다.
가장 마지막 데이터의 id 값을 모르기 때문에, 다음 id를 설정할 수 없기 때문이다.

물론 개발자도 일일이 id를 검색해서 입력해줄 수는 없다.
그래서 이를 해결하기 위해 id 값의 자동 증가를 구현할 필요가 있다.

방법

  1. id 값을 관리할 모델을 생성한다.(Counter.js)
  2. id 값을 증가시킬 모델의 신규 데이터가 save()된 후 해당 id 값에 접근한다.(User.js)
  3. Counter.js에서 적절한 값을 찾아 증가시킨 뒤, User.js의 모델의 id값으로 넣어준다.

말로 표현하려니 약간 어색하다.
코드로 살펴보자.

구현

// Counter.js

const mongoose = require("mongoose");

let CounterSchema = mongoose.Schema({
  id: {
    type: Number,
    default: 0,
  },
  userIdCounter: {
    type: Number,
    default: 0,
  },
  lectureIdCounter: {
    type: Number,
    default: 0,
  },
  contentIdCounter: {
    type: Number,
    default: 0,
  },
});

const Counter = mongoose.model("Counter", CounterSchema);

module.exports = { Counter };

위에서 말했던 3가지의 모델을 위한 counter를 각각 만들어놨다.
각 모델에 대해 하나씩 매칭되게 Counter.js를 분리해서 만들어버리면,
컬렉션에 있는 공간을 쓸데없이 차지할 것 같아 하나의 컬렉션에 key-value로 만들어놨다.

아, 참고로 id라는 key는 나중에 데이터 찾기 편하려고 필자가 일부러 만들어놓은 것이다.

이제 특정 모델의 신규 데이터가 저장될 때, 저 3개의 값 중 해당하는 값을 찾아서 사용하면 된다.

자, 이제 신규 데이터가 생성되었다고 가정해보자.
save() 메서드를 사용해서 DB에 저장할 것이다.
저장 직후(post) 가동될 로직을 아래와 같이 만들었다.

// User.js

// ... //
const mongoose = require("mongoose");

const userSchema = mongoose.Schema({
  userId: {
    type: Number,
    default: 0,
  },
  
  // ... //
}
                                   
const { Counter } = require("./Counter");

// 유저 데이터의 save()가 완료된 후 작동하는 코드
userSchema.post("save", function (result) {
  // 등록된 유저의 정보를 가져옴.
  let user = this;

  // Counter 모델에 id가 0인 데이터를 찾는다.
  // Counter 모델은 데이터가 id가 0인 것 하나밖에 없다.
  // 3가지의 counter를 key-value로 넣어놓았을 뿐이므로..
  Counter.findOne({ id: 0 }, (err, res) => {
    if (err) return err;

    // Counter 모델에서 찾은 데이터의 userIdCounter를 1 증가시킨다.
    let up = res.userIdCounter + 1;

    // 다시 id가 0인 데이터를 찾아서 업데이트를 진행한다.
    // userIdCounter를 증가시키고싶으므로 userIdCounter에 새로운 값을 넣어준다.
    Counter.updateOne({ id: 0 }, { userIdCounter: up }, (err) => {
      if (err) return err;

      // Counter 모델의 값을 증가시켜놨으니, User 모델의 값을 증가시키자.
      // 등록된 유저의 정보의 이메일과 일치하는 데이터를 찾아서
      // userId를 up으로 수정해준다.
      User.updateOne({ email: user.email }, { userId: up }, (err) => {
        if (err) return err;
      });
    });
  });
});

이제 데이터를 여러개 추가해보자.

참고 이미지

userId라는 key의 value가 자동적으로 증가하는 것을 확인할 수 있다!

참고로, Counter.js의 모델을 생성해놓고 진행하는 것이므로 주의하셔야한다.
왜 컬렉션에 안 생기지? 이럴 수 있는데,
코드에서 Counter 모델을 한번 생성하고 다시 코드를 지운 뒤부터 위 방법들을 사용하시면 된다.
한 번 생성하면 컬렉션에 생길 것이고,
그 뒤로는 거기에 들어있는 하나의 데이터에서 key-value만 변환하면서 사용하기 때문이다.

참고 자료

참고 자료 1
참고 자료 2
참고 자료 3
참고 자료 4
참고 자료 5
참고 자료 6
참고 자료 7

profile
나를 믿는 사람들을, 실망시키지 않도록

0개의 댓글