MongoDB TTL 설정

jh_leitmotif·2021년 11월 6일
0

이것저것..TIL

목록 보기
9/9
post-thumbnail

개요

웹 커머스에선 적립금, 쿠폰 등을 활용하곤 합니다.

각각은 보통 유효기간이 설정되는 편이고, 이를 MongoDB에서 설정하는 것을 정리합니다.

참고 링크 : https://docs.mongodb.com/manual/tutorial/expire-data/

TTL이란?

TTL : Time To Live. 컴퓨터나 네트워크에서 데이터의 유효 기간을 나타내기 위한 방법. 정해진 유효기간이 지나면 데이터는 폐기된다.
// 출처 : 위키백과

전산상에 존재하는 데이터의 유효 기간을 나타내는 방법입니다.

IP 계층에서는 IP 데이터그램이 인터넷에서 존재하는 상한선을 의미하며

DNS 레코드에서는 캐시된 주소의 유효기간입니다.
해당 주소의 TTL이 지나지 않았다면 구태여 네임서버에 접속하지 않고 캐시된 데이터를 이용해 주소로 접근하게 됩니다.

이 포스트에서 서술할 MongoDB에서는 생성된 document에 대해 TTL Index를 적용하여 유효기간을 설정합니다.

MongoDB의 경우.

MongoDB Shell, mongosh 환경에서 조작하는 경우에 대해서 다룹니다.

예를 들어, collection의 이름을 'coupons'이라고 합니다.

db.coupons.createIndex({expiredAt:1},{expireAfterSeconds:3600})

이제 col1에 있는 docs 중 field라는 필드 네임을 가진 문서는 1시간 뒤에 삭제되도록 설정되었습니다!

여기에서 주의해야할 것은 field의 값 + 3600s에 해당하는 시간에 만료되므로

field는 단독의 Date 값을 가지거나, 혹은 Date Array가 되어야합니다.

Mongoose의 경우

Node에서 Mongoose를 이용해 스키마를 정의하고, 저장할 때의 경우입니다.

1. Define in schema

간단합니다. 필드에 expires:n 형태로 정의하면 됩니다.

위의 코드를 보게 되면,

createdAt 필드는 현재 시각을 default로 가지는 Date 값이며

60초의 expireAfterSeconds 값을 가집니다.

즉 이 couponSchema는 생성된 시각 + 60초가 되면 만료되어 삭제됩니다.

딱 60초가 되어 삭제되지는 않았는데,
이 부분은 DB와 통신할 때 생기는 자연스러운 딜레이인 것 같습니다.

2. Create index after define schema

mongosh에서 하는 것과 비슷합니다.

스키마를 생성하고, 모델로 잡아준 뒤

collection.schema.index({field:1},{expireAfterSeconds:xx})

와 같은 방식으로 지정하면 첫 번째 방법과 같은 형태로 작용합니다.

3. Create index with timestamp

let currentSchema = mongoose.Schema({
    id: String,
    name: String,
    packageId: Number,
    age: Number
}, {timestamps: true});

currentSchema.index({createdAt: 1},{expireAfterSeconds: 3600});

참고 링크:https://stackoverflow.com/questions/14597241/setting-expiry-time-for-a-collection-in-mongodb-using-mongoose

위의 참고 링크에서 확인한 방법입니다.

스키마를 정의할 때 2번째 파라미터로

{timestamps: true}

를 넣어주면 현재 시각을 값으로 한 createdAt 필드가 생성됩니다.

그 뒤는 2번째 방법과 같습니다.

Set TTL to each docs

위의 방법들은 생성된 시각을 기준으로 지정된 초가 지나면 만료가 됩니다.

하지만 쿠폰 중에는 게릴라성도 있고, 만료되지 않아야할 것도 있습니다.

다행스럽게 MongoDB공식 문서에는 이를 위한 방법이 설명되어 있습니다.

링크는 맨 위에 있습니다.

각 docs에 대해 만료시간을 따로 지정하는 방법은, expireAfterSeconds값을 0으로 지정하는 것입니다.
이 경우, 색인된 필드의 Date 값이 현재 시각보다 과거로 판정된다면
만료된 것으로 간주하고 삭제합니다.

이렇게하면 굳이 expireAfterSeconds 값을 지정하지 않고
직접 각각의 document에 만료될 date를 지정해주기만 하면 됩니다.

Set Coupon document

먼저 coupon schema를 작성합니다.

문서의 설명과 같이
만료될 날짜가 저장될 expiredAt 필드에 expires:0 을 작성합니다.

addCoupon function의 일부분입니다.

couponDuration은 사용자가 전송한 유효기간을 의미합니다.

24x3600x1000 은 timestamp에서 1일을 의미하게 되며
여기에 만약 30을 곱해주면 곧 30일이 될겁니다.

setUTCHours(0,0,0,0)을 해준 것은,
유효기간이 날짜의 범위로 한정되어야하지

시/분/초의 범위까지 확장되는 경우엔 이용자의 입장에서 사용에 불편함이 있기 때문입니다.

시/분/초를 초기화하는 함수는 setHours, setUTCHours가 있습니다.
1. setHours: 현지 시각을 기준으로 시간이 조정된다.
2. setUTCHours: 표준시를 기준으로 시간이 조정된다.

의도에 반하여 해당 날짜의 1일 전날 자정으로 시간이 초기화되는 경우가 있습니다.
저는 setHours가 react에선 정상이었지만 node에서 문제가 있어
setUTCHours로 통일하게 되었습니다.

결과

의도한대로 쿠폰이 잘 생성되었습니다.

TTL Index도 정상적으로 생성되어 있습니다.

위의 쿠폰은 내일인 11월 7일 0시가 되면 삭제될 것입니다.

profile
Define the undefined.

0개의 댓글