시간의 흐름에 따라 발생하는 데이터 (주로 센서 데이터, 금융 데이터, 로그 데이터 등 다양한 형태로 존재)
이를 효율적으로 분석할 수 있도록 제공함 → 시간이 들어간 개념!
시계열 데이터를 효율적으로 저장하고 쿼리하기 위해 설계된 특수한 컬렉션 유형
✔ 시계열 데이터를 효율적으로 저장하고 컨트롤하는 기능
✔ 동일한 출처의 데이터가 비슷한 시점의 다른 데이터 포인트와 함께 저장되도록 쓰기가 구성된다.
자동으로 생성된 클러스터형 인덱스를 사용 → 데이터를 time-series 순서로 저장
일반 컬렉션처럼 동작
MongoDB는 시계열 컬렉션을 내부 컬렉션에 의해 뒷받침되는 쓰기 가능한 비물질화 뷰로 취급
time-series 컬렉션에 대한 쿼리는 최적화된 내부 저장 형식 활용 → 속도가 아주 개선됨
특징
timeField와 metaField 필수 지정 → 데이터 삽입할 때에도 타임필드와 메타데이터를 포함하여 작성
조회 시 일반 컬렉션과 동일한 쿼리 사용, 집계 쿼리 사용해 분석 가능
-- 시계열 컬렉션 생성
db.createCollection("sensorData", {
timeseries: {
timeField: "timestamp",
metaField: "metadata",
granularity: "minutes"
}
});
-- 데이터 삽입
db.sensorData.insertMany([
{
timestamp: ISODate("~"),
metadata: { sensorId: 1, location: "Room1" },
temperature: 22.5,
...
},...
]);
timeField
- 시간 정보 저장metaField
- 메타데이터 저장 (데이터 설명)granularity
- 데이터의 시간 간격(optional)timeField와 metaField를 효과적으로 사용하기 → 각각 타임스탬프와 데이터 출처를 식별하는 메타데이터로 정의하여 구조화하면 유사한 시계열 데이터가 함께 그룹화되어 저장된다
적절한 Granularity 설정 (seconds, minutes, hours) → 저장 공간과 쿼리 성능 최적화
insertMany()
로 일괄 삽입하며 오버헤드가 줄고 데이터가 최적화된 형태로 그룹화 되어 저장 MongoDB의 집계 프레임워크는 시계열 데이터를 분석하는데 적합
.$group
→ 특정 시간 창에 대한 평균, 합계 또는 개수 계산
버킷팅(Bucketing) → $bucket
또는 $bucketAuto
를 통해 데이터를 특정 간격으로 그룹화
db.temperatureReadings.createIndex({ timestamp: 1}, { expireAfterSeconds: 60 * 60 * 24 * 30 });
use timeSeriesTestDB
db.createCollection("environmentSensors", {
timeSeriese: {
timeField: "timestamp",
metaField: "sensorInfo",
granularity: "minutes"
}
});
* metaField 필드에 대해 동일한 고유 값을 가진 연속 수신 측정값 사이의 시간 범위와 가장 가까운 값으로 세분성을 설정합니다.
* 연속적으로 들어오는 타임스탬프 사이의 시간과 가장 근접하게 일치하는 값으로 granularity 를 설정합니다. 이렇게 하면 MongoDB가 컬렉션에 데이터를 저장하는 방법을 최적화하여 성능이 향상됩니다.
👉 이걸 왜 쓰는지 약간 이해가 잘... 안 갔는데 granularity를 설정하면 데이터를 저장하는 방식에서 최적화가 되는 것 같음 내부적으로 어떻게 작동하는지는 모르겠으나 ... 참고
sensorId
, location
정보 저장 (자동 인덱싱) temperature
, humidity
db.environmentSensors.find({
timestamp: {
$gte: ISODate("2024-07-22T08:00:00Z"),
$lt: ISODate("2024-07-22T08:10:00Z")
}
});
timestamp 데이터가 2024-07-22T08:00:00Z 이상, 2024-07-22T08:10:00Z 미만인 정보를 조회한다
결과 화면
db.createCollection("stockPrices", {
timeseries: {
timeField: "timestamp",
metaField: "stockInfo",
granularity: "hours"
}
})
ticker
db.stockPrices.aggregate([
{
$match: {
timestamp: {
$gte: ISODate("2024-07-21T09:00:00Z"),
$lt: ISODate("2024-07-21T12:00:00Z")
}
}
},
{
$group: {
_id: "$stockInfo.ticker",
avgOpen: {$avg: "$open"},
avgClose: {$avg: "$close"}
}
}
])
#1. $match
→ 지정된 쿼리 조건자를 기준으로 문서를 필터링
timestamp 기준으로 2024-07-21T09:00:00Z 이상, 2024-07-21T12:00:00Z 미만의 데이터를 필터링 해 다음 파이프라인으로 넘긴다
#2. $group
→ '그룹 키'에 따라 문서를 그룹으로 분리
그룹키 : stockInfo의 ticker를 기준으로 그룹을 분리한다
avgOpen : $avg
함수로 그룹 내의 $open
데이터의 평균을 구한다
avgClose : $avg
함수로 그룹 내의 $close
데이터의 평균을 구한다
결과 화면
우리가 가진 데이터에서 stockInfo.ticker
는 'AAPL' 값 밖에 없었기 때문에 AAPL 데이터 그룹 한 개만 출력된다. 아래는 평균값들!
db.createCollection("iotDeviceEvents", {
timeseries: {
timeField: "eventTime",
metaField: "deviceInfo",
granularity: "seconds"
}
})
eventTime
이 되었다!deviceInfo
가 저장된다deviceId
와 type
으로 구성event
와 value
값으로 구성db.iotDeviceEvents.find({
"deviceInfo.deviceId": "device1"
}).sort({eventTime: -1}).limit(1)
find()
→ 문서를 선택하고 선택한 문서로 커서를 반환
deviceInfo의 deviceId가 "device1"인 문서를 선택하여 커서를 반환
sort()
→ 정렬
eventTime 기준으로 내림차순 정렬
limit()
→ 출력되는 데이터 수 제한 (1개)
결과 화면
우리가 데이터 출력 개수를 하나로 제한했기 때문에 위와 같은 데이터가 출력된다
만약 limit()
함수를 제외한다면
위와 같이 데이터가 정렬된다. 우리가 선택한 문서들 중 eventTime 기준 내림차순으로 정렬이 되었음을 알 수 있다.
실습 문제를 다시 한 번씩 작성해보고 정리하다보니까... 뭔가 알 것 같기도...? 하지만 아직은... 혼자서 함 써봐! 하면 너무 어려울 것 같다... 흑흑 몽고디비 이상해 ㅠㅠ
본 포스팅은 글로벌소프트웨어캠퍼스와 교보DTS가 함께 진행하는 챌린지입니다