Middlewares

0_CyberLover_0·2022년 4월 14일
0

Node.JS # 03

목록 보기
17/19

만약 update할때 마다 콘솔에서 useFindAndModify optionset to false..
같은 경고를 받는다고 가정 한다.

걱정할 필요 없다. 단순하게 useFindAndModifyDB안에 추가하면 된다.

(현재 mongooseuseFindAndModify는 기본값이 false로 되어 있어서

에러가 뜨지 않는다. 그러므로 따로 useFindAndModify 안해줘도 된다.)

db.js에서

mongoose.connect("mongodb://127.0.0.1:27017/wetube", {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  useFindAndModify: false,
});

이제 hook 혹은 middleware라고 불리는 거에 대해 알아본다.

그러니까 Mongoose에서 middleware라는건

https://mongoosejs.com/docs/middleware.html

request를 중간에서 가로채서 뭔가를 하고 이어서 진행하는 거다.

Express에 있는 어떤 middleware는 뭔가를 하고 next를 콜한 다음 request를 계속 처리 한다.

도움이 될만한 예는 morgan middleware가 있겠다.

Mongoose에서도 똑같다. document에 무슨 일이 생기기 전이나 후에 middleware를 적용할수 있다.

예를 들면 save하기 전,후로 middleware를 적용하거나 function을 실행 할수 있다.

혹은 update하기전이나 후에 말이다. 그리고 Expressmiddleware같이 흐름을 방해하지 않는다.

중간에 뭔가를 할뿐 그후에는 흐름을 이어간다.

일단 database에 있는 비디오들을 다 삭제 한다.

하지만 계속하기전에 Mongoose에서 middleware는 어떻게 생겼는지 본다.

schema.pre('save', async function() {
  await doStuff();
  await doMoreStuff();
});

사실 굉장히 간단하다. save그리고 function들을 실행만 시키면 된다.

그럼이제 model폴더 안 video.js로 가서 여기서 첫번째 middleware를 만들어 본다.

하지만 한가지 중요한 것은 middelware무조건 model이 생성 되기전에 만들어야 한다.

const videoSchema = new mongoose.Schema({
  title: { type: String, required: true, trim: true, maxLength: 80 },
  description: { type: String, required: true, trim: true, maxLength: 20 },
  createdAt: { type: Date, required: true, default: Date.now },
  hashtags: [{ type: String, trim: true }],
  meta: {
    views: { type: Number, default: 0, required: true },
    rating: { type: Number, default: 0, required: true },
  },
});

videoSchema.pre('save', async function(){
  
})

const Video = mongoose.model("Video", videoSchema);
export default Video;

그러니 위치는 저곳에다가 만들어 준다. middelware로 호출된 async function을 보낸다.

이제 설명서를 보면 이 middleware에 관해 하나있는데

https://mongoosejs.com/docs/middleware.html

여기 있는 middleware들 중에 현재save를 만드는 중이고 function안에 this라는 키워드가 있다.

그리고 이 this는 우리가 저장하고자 하는 문서를 가리키는 거다.

그럼 시험삼아 thisconsole.log해 본다.

videoSchema.pre("save", async function () {
  console.log(this);
});

그리고 이젠 새 document 새로운 영상을 만들건데 그것을 console.log할 거다.

한가지 더 추가한다.

  console.log("We are about to save:", this);

이제 준비 되었다. 그럼 이제 생성해 본다. upload video에서 제목,상세설명,해시태그들을 적어준다.

비디오는 잘 생성되었고 console을 확인해 보면

GET / 304 169.335 ms - -
GET /videos/upload 200 36.764 ms - 814
We are about to save: {
  title: 'Someting with HTML',
  description: 'Delicious',
  hashtags: [ '#for', '#real', '#now', '#mongo' ],
  meta: { views: 0, rating: 0 },
  _id: new ObjectId("62575d76b224e2c022b66c88"),
  createdAt: 2022-04-13T23:32:06.328Z
}
POST /videos/upload 302 39.178 ms - 46
GET / 200 44.298 ms - 656
GET /videos/62575d76b224e2c022b66c88 200 27.969 ms - 666

잘 되고 있다. 작동 하는걸 확인 했으니 원한다면 이것 저것 바꿔 볼수 있다.

원하는대로 아무거나 바꿔 볼수 있다.

예를 들면 여기에서

videoSchema.pre("save", async function () {
  console.log("We are about to save:", this);
  this.title = "Hahaha! Im a middleware!!";
});

이런식으로 변경해 본다. document를 수정 할 수도 있다. 왜냐하면 저 부분은 save

되기전에 실행 되기 때문이다. 다 javascript에서 하는거다.

그러면 다시 한번 upload video로 가서 입력하면 제목이 입력한게 아닌 미리 해 놓았던

제목으로 변경이 되어있다. 이런식으로 아무거나 마음대로 바꿀수가 있다.

이제 하려는건

videoController.js에서

hashtags: hashtags
      .split(",")
      .map((word) => (word.startsWith("#") ? word : `#${word}`)),

여기 create에 있는 hashtags funcrtion을 지운다.

export const postUpload = async (req, res) => {
  const { title, description, hashtags } = req.body;
  try {
    await Video.create({
      title,
      description,
      hashtags,
    });

어떤 결과가 나올지 한번 보도록 한다. 이 object가 어떻게 저장될지 console.log로 본다.

video.js에서

videoSchema.pre("save", async function () {
  console.log(this);
});

그리고 이렇게 수정해 주고 이제 hashtags에 대해서 아무 처리도 하지 않을때

video가 어떻게 저장 되나 본다. 이 경우에 hashtahs는 단순히 이런 stirng이 될거다.

hashtags: "1,2,3,,5,46.,",

array가 아니라 왜냐하면 프론트엔드에서 오는 hashtags는 그냥 문자열일 뿐이기 때문이다.

새로고침 한다음 Upload Video를 해주면 제대로 작동하고 그리고 보이듯이

hashtags에는 당연히 아무런 처리가 되지 않았다. console을 보면 hashtags가 저장되는 법도 다르다.

이게 무슨 의미 냐면 만약에 해시태그로 string을 입력한다면 Mongoose가 자동으로

array방식으로 변환 시킨다는 거다. 하지만 나뉘어져 있지는 않다.

단순히 입력된 문자열을 array의 첫번째 element로 지정하는 거다.

Mongoose는 도와주려고 하는거고 에러도 없지만 schema를 만들때 hashtags

string array라고 했기 때문에 프론트엔드에서 보낸 정보가 그냥 통째로array로 들어가게 된거다.

이전과는 완전히 다르다. 이전은 4개의 element를 가진 array였고

지금은 1개의 string element만 가진 array이다.

이제 object가 데이터베이스에 어떻게 저장되는지 알았으니 바꾸고 싶은건
hashtags array의 첫 element가 포맷되는 방식이다.

그걸 위해 이렇게 해본다.

videoSchema.pre("save", async function () {
  this.hashtags = this.hashtags[0]
    .split(",")
    .map((word) => (word.startsWith("#") ? word : `#${word}`));
});
this.hashtags = this.hashtags[0]

이게 array이니깐 여기서 첫번째 elemnet를 뽑는거다.

이걸 콤마를 기준으로 나눌거고 그리고 map(word) 이전에 했던 거다.

hashtags 기호로 시작하면 wordreturn할 텐데 아니라면 앞에 hashtags를 붙여서 return 이다.

다시 말하자면 이렇게 하는 이유는 이렇게 하지 않으면 input에 입력된 값이 하나의 elementarray에 입력 되기 때문이다.

그래서 첫번째 개체를 받은 다음에 #을 붙이는 걸 하는게 이 부분이다.

그러기전에 일단 데이터베이스에 가서 db.videos.remove를 해준다.

그러면 이제 아무 영상도 없게 된다. home으로 가면 아무것도 없다.

이제 Upload Video에서 제목, 설명, 해시태그들까지 입력하면 해시태그들을 보면 제대로 처리 되어 있다.

그럼 이제 mongodb에서 videos를 확인해 본다.

현재 단 하나뿐이 video object가 있다. 해시태그를 보면 잘 적용 되어 있다.

보다시피 이게 pre middlewaresave이벤트에 적용시킨 결과이다.

videoSchema.pre("save", async function () {
  this.hashtags = this.hashtags[0]
    .split(",")
    .map((word) => (word.startsWith("#") ? word : `#${word}`));
});

하지만 이건 update시에는 아무런 도움도 되지 않는다.

그러니까 update를 위한 middleware가 하나 더 필요 하다.

profile
꿈꾸는 개발자

0개의 댓글