타입 안전성을 제공하는 Elasticsearch 집계 TypeScript 라이브러리
Elasticsearch의 복잡한 집계 쿼리에 대해 타입 추론과 자동완성을 제공합니다.
npm install elasticsearch-aggregation @elastic/elasticsearchinterface UserDocument {
id: string;
name: string;
age: number;
email: string;
automationActionId: string;
status: string;
profile: {
bio: string;
location: string;
preferences: {
theme: "light" | "dark";
notifications: boolean;
};
};
stats: {
postsCount: number;
followersCount: number;
};
tags: string[];
}import { Client } from "@elastic/elasticsearch";
import './elasticsearch-aggregation'; // typedSearch 확장
const client = new Client({
node: "http://localhost:9200"
});
const response = await client.typedSearch<UserDocument>({
index: "users",
query: { match_all: {} },
aggs: {
group_by_automationActionId: {
terms: {
field: "automationActionId",
size: 100,
},
aggs: {
groupByStatus: {
terms: {
field: "status"
}
},
},
},
},
});
// 타입 추론
const buckets = response.aggregations?.group_by_automationActionId.buckets;
buckets?.forEach(bucket => {
console.log(bucket.key); // string
console.log(bucket.doc_count); // number
console.log(bucket.groupByStatus.buckets); // 중첩 집계 결과
});// 숫자 필드만 histogram에 사용 가능
const response = await client.typedSearch<UserDocument>({
aggs: {
ageHistogram: {
histogram: {
field: "age", // ✅ number 필드
interval: 5
}
},
// field: "name" // ❌ 컴파일 에러: string 필드는 histogram에 사용 불가
}
});// 깊은 중첩 필드 지원
const response = await client.typedSearch<UserDocument>({
aggs: {
themeDistribution: {
terms: {
field: "profile.preferences.theme" // ✅ 3단계 중첩 필드
}
}
}
});const response = await client.typedSearch<UserDocument>({
_source: ["name", "profile.location"], // ✅ 타입 안전한 필드 선택
aggs: {
topHits: {
top_hits: {
_source: ["email", "age"] // ✅ 집계별 source 설정
}
}
}
});
// _source 설정에 따른 타입 추론
response.hits.hits.forEach(hit => {
console.log(hit._source.name); // ✅ string
console.log(hit._source.profile.location); // ✅ string
// hit._source.age // ❌ 컴파일 에러: _source에 포함되지 않음
});const dashboardData = await client.typedSearch<UserDocument>({
index: "users",
size: 0,
aggs: {
// 사용자 통계
totalUsers: {
value_count: { field: "id" }
},
avgAge: {
avg: { field: "age" }
},
// 지역별 분포
locationDistribution: {
terms: {
field: "profile.location",
size: 10
},
aggs: {
avgAge: { avg: { field: "age" } },
statusBreakdown: {
terms: { field: "status" }
}
}
},
// 연령대별 그룹
ageGroups: {
histogram: {
field: "age",
interval: 10
},
aggs: {
avgPosts: {
avg: { field: "stats.postsCount" }
}
}
}
}
});
// 타입 추론으로 안전한 데이터 접근
const stats = {
totalUsers: dashboardData.aggregations?.totalUsers.value || 0,
avgAge: dashboardData.aggregations?.avgAge.value || 0,
locationData: dashboardData.aggregations?.locationDistribution.buckets.map(bucket => ({
location: bucket.key,
count: bucket.doc_count,
avgAge: bucket.avgAge.value,
statusBreakdown: bucket.statusBreakdown.buckets
})),
ageGroups: dashboardData.aggregations?.ageGroups.buckets.map(bucket => ({
ageRange: `${bucket.key}-${bucket.key + 10}`,
count: bucket.doc_count,
avgPosts: bucket.avgPosts.value
}))
};이 라이브러리는 다음과 같은 고급 TypeScript 기능을 사용합니다:
- 조건부 타입 (Conditional Types): 집계 타입에 따른 결과 타입 추론
- 템플릿 리터럴 타입: 중첩 필드 경로 생성 (
profile.location) - 매핑된 타입 (Mapped Types): 집계 결과 객체 타입 생성
- 타입 추론 (Type Inference):
as const와 함께 정확한 리터럴 타입 추론