30~06.Dec.2020

Q kim·2020년 11월 30일
1

개발 일기

목록 보기
2/6

12월 첫째주
이번주는 API 문서화해놓은 그대로 구현만 할듯하다. 어쩌다보니 나 혼자 해야해서 다른 공부는 힘들듯하다.
CRUD 하면서 mongoDB query를 꽤 많이 볼듯하니 "대충대충 이거면 되겠지~"하며 넘어가는 일은 없도록 하겠다.

30일_ CRUD, 근데 이제 "mongoDB"를 곁들인, [기능구현하기]

1. 주말에 작업한 코드 옮기기(램 8기가는 좀 힘들다.)

내가 놋북을 정리안하면서 써서 그런 것일수도 있지만, (그럴 가능성은 적다.) 놋북의 램이 문제일 가능성이 90%다.
TypeScript를 쓰면 컴파일이 너무 오래걸려서 흐름이 정말정말정말 잘 깨진다. 그래서 집에선 TypeScript가 필요없는 작업이나 필요한 개념들을 공부하는 위주로 노트북을 쓴다. 그런데 일이 너무 급해서 clone한후 작업을 시작하니 npm i부터 너~~무 오래 걸린다. install은 한번이니 참을수 있다. 문제는 코드가 바뀔때마다 컴파일될 때 거의 30초정도나 걸리다보니 너무 집중이 안되버린다.

주말에 테스트없이 작성한 코드들부터 합친뒤 테스트하고 CRUD 노가다 시작..

2. findByIdAndUpdate() - runValidators: true

# 문제:
mongoose 스카미 enum에 설정해둔 값 이외의 값으로 수정이 된다. validationError가 발생하지 않는다.

mongoose function인 findByIdAndUpdate()를 써서 수정 기능을 만들고 있었다.

모델 예시.

const SomeSchema = new mongoose.Schema({
  field1: {
    type: String,
    enum: ['1', '2', '3'],
    required: true,
    default: '1'
  }
});

사용한 함수는

await SomeSchema.findByIdAndUpdate(modelID, { field1: '0' }, { new: true });

enum이 제대로 작동하나 확인할 겸 Schema에 세팅해놓지 않은 enum 값('0')을 넣어봤다. 예상대로라면 에러(ValidationError)가 나와야 하는데 그냥 '0'으로 수정이 된다.

그래서 검색해보니 (검색 키워드: "mongoose enum restrict")

# 해답:
you have to pass the runValidators option to get it:
{ runValidators: true }

바꾼 함수는

await SomeSchema.findByIdAndUpdate(modelID, { data }, { new: true, runValidators: true});

하루 마무리:

  • CRUD 노가다 중이라서 적을게 없다. 역시나 CRUD 노가다만큼 집중잘되는 것도 없긴하다.
    (하지만 딱히 남는건 없는..)
  • 다행히 달리기를 잠깐이라도 했다. 매일좀 하자. !

1일_ CRUD의 주.

1. 어제 했던 기능 다음 것부터 구현 시작.

2. 외부 입력값 validate - Joi

이전 프로젝트까지는 외부 입력값 확인을 손수 만들어서 썼었는데 이번에는 외부 라이브러리를 써보려고 한다.
"joi" 한번 훑어보니 아주 쉬워보인다.

# 하루 사용해본 소감:
내가 손수 validation 함수를 작성했다면 에러 종류에 따라 분기하느라 빠뜨리는게 있을 텐데 joi는 다 되어있어서 수월했다. library가 편하긴 하다..!

읽은 자료: https://gumpcha.github.io/blog/joi-overview

3. 아주 간단한 Text Search '$like'

"데이터 양이 아주 적다면 쓸만한 쿼리다. 정말 아주 적을 때만/ 정석적인 문자열 검색은 full text indexing을 검색해보자 !

회사 기존 서비스를 건드릴 필요가 생겼다. "tag 검색이었던 기능을 Text Search로 바꿔줄수 있느냐"라는 요청. "text 검색하려면 index를 설정해뒀어야 하지 않나?" 궁금증이 들었다. 결론은. "지금 상태로도 가능하다." 이미 저장되어있는 데이터가 많더라도 DB를 다시 설정하면 된다.
문제는 딱 하나가 있다. 데이터가 너무 많으면 index 생성하는데 시간이 많이 들어 서비스를 그 시간동안 이용할 수 없게 된다. 그뿐이다.

작업을 하려는 서비스의 상황은 이렇다.
서비스 개편/확장중이라 당분간 데이터가 추가될 일이 없다. 그리고 데이터의 갯수가 1000개도 안된다.
때문에 $like 연산자로 검색하면 되지않나? 생각이 들었다.

이 생각으로 이전 서비스 코드를 처음 까봤다. DB를 둘러보니 text search의 대상중에 30% 정도가 문자열로 저장되어있지 않고 숫자로 저장되어 있었다. 대표적으로 카테고리가 그랬다. 동물을 예를 들면 "사자는 1, 호랑이는 2, 고양이는 3" 이렇게말이다. 이렇게 저장되어있으니 DB단에서 text search를 하는게 너무 힘들어졌다. 서버단에서 카테고리를 위한 코드를 따로 짜셔 해야하나 생각도 해봤는데 회사 개발 일정상 이전 서비스에 너무 많은 시간을 들이기는 힘든 상황이라(현재 새 서비스 MVP개발중) 간단히 하고 넘어가야했다. 결론은 DB에 숫자로 저장되어있는 값들을 제외하고 $like연산자를 이용하기로 했다.

기존 쿼리를 들어오는 input에 대해서 like연산 실행시키고 순식간에 끝나버렸다. ㅎㅎ...

# 결론: "데이터 값들을 숫자로 바꿔서 저장해두면 서비스 확장때 힘들수도 있다. DB 설계할때 유의 !"

하루 마무리

역시나 남의 코드 까보는건 힘든일이다. 그러나 재밌다. 좋은 코드를 보면 감탄을 하게 되고, 이상한 코드를 보면 이렇게 정~말 돌아가게만 짜는 사람도 있구나~ 느낀다.


2일_ 다시 CRUD CRUDCURDCURD

1. mongoDB query를 자세히 익혀야한다.

한 document에 계층이 있는 상태로 데이터베이스에 저장이 되는데 계층이 깊은 곳의 데이터를 건들이는 방식을 제대로 알아야 한다.

RDB에서는 사람-주문 person-photo을 관계로 이어준다면, MongoDB는 사람(person) document안에 photo를 통째로 넣어버린다. 여기서 잘몰랐었던 것이 처음에는 photo가 특별한 의미가 없을 때라서 photoURI만 넣어두려고
photos array list를 만들어 둔다음에 photoURI만 넣어줬었다.

person: {
    '_id': "id1",
    'orders': [
        'ordername1',
        'ordername2',
        'ordername3'
    ]
}

요렇게.

그런데 문제는 이렇게 id값없이 list로 저장해두면
1. 수정, 삭제할때 id로 검색하는 것이 아니라 photoURI로 검색해야한다는 것
2. mongoDB query에서 검색이 힘들어진다는 것이다. json으로 저장되는 mongoDB에서 object로 저장되어있지 않고 단순 list로 저장되어있다면 리스트의 특정 값을 검색하는게 힘들어진다. 하려면 모델을 통째로 받아온다음에 .save시켜야하는데 이러면 쿼리를 두번날리게 되는 것이다. 한번 쿼리에 모델을 수정할 수 있어야 한다.

하루 마무리

MongoDB에 점점 더 깊히 빠져들고 있다.

3일_ 휴무 / 임플란트한 날...

4일_ mongoose query

1. $set { overwrite: true } _mongoose

# 문제:
$set 을 이용해서 nested array의 값을 수정하는 중이었다. 하라는 데로 잘 query했는데
수정하지 않는 값들은 아에 사라져버린다. 그리고 _id 까지 바뀌어버렸다. 수정하는 것이 아니라 없애고 새로 만들어버리나보다.

# 해결:
찾아보니 option으로 overwirte: true 을 주라고 한다.

NOTE The true way to "replace" would actually be to use replaceOne, either as the API method of replaceOne() or through bulkWrite(). The overwrite is a legacy of how mongoose wants to apply $set as described and demonstrated above, however the MongoDB official API introduces replaceOne as a "special" king of update() operation which does not allow the usage of atomic operators like $set within the statement and will error if you try.
This is much clearer semantically since replace reads very clearly as to what the method is actually used for. Within standard API calls to the update() variants of course still allow you to omit the atomic operators and will just replace content anyway. But warnings should be expected.
출처: https://stackoverflow.com/questions/45182011/mongoose-overwrite-the-document-rather-that-set-fields

2. $push $each

#상황
array인 필드에 복수개의 데이터를 집어 넣을 때는 $each 연산자를 쓰면 된다.

db.inventory.update(
   { _id: 2 },
   { $addToSet: { tags: { $each: [ "camera", "electronics", "accessories" ] } } }
 )

3. subdocument create

const Subdoc = {
	a: String
}

modelA = {
	_id: mongoose.schema.types.objectID,
  	fieldA: String,
  	subdoc: [Subdoc]
}

let array = [];
for (let i = 0; i < subdocInput.length; i++) {
  var obj = {};
  obj['a'] = subdocInput[i];
  array.push(obj);
}

let checkSubdoc;
if (youtubeURIs) {
  // push youtubeURIs
  createSubdoc = await this.ModelA
    .findOneAndUpdate(
      { _id: ModelA._id }, 
      { $push: { subdoc: { $each: array } } }, 
      { new: true });
}

"mongoose Schema를 정의할때 [String] 보다 [Subdoc]이 더 활용성이 좋다."
값들을 저장할 때 [String]으로 저장할때가 있는데 되도록이면 subdoc으로 만드는 것이 훨씬 나중에 편할 확률이 높다. [Subdoc]이렇게.
왜냐면 subdoc으로 저장하면 _id가 생성되기 때문에 삭제, 수정을 할때 특정 요소만 수정,삭제하기 수월해진다. array에서도 $pull을 해서 삭제하면 되지만 수정할때는 특정 인덱스를 꼽아서 수정하는것이 불가능하다. query를 두번날려서(1.읽어온뒤 수정해서 2.다시 저장)할수 있지만 query는 최소한으로 날려야하는게 성능에 좋기때문에!

5일,6일_ 주말에도 일~

1. 간편 crud구현만 하루종일 했다. 주말 평일은 없다..

profile
https://medium.com/nodejs-server

0개의 댓글