버킷 패턴으로 데이터 그룹화하기
이 페이지의 내용
버킷 패턴은 긴 데이터 시리즈를 별개의 객체로 분리합니다. 큰 데이터 시리즈를 작은 그룹으로 분리하면 쿼리 액세스 패턴을 개선하고 애플리케이션 로직을 간소화할 수 있습니다. 버킷팅은 단일 사용자의 주식 거래와 같이 중앙 엔터티와 관련된 유사한 객체가 있을 때 유용합니다.
애플리케이션이 페이지당 표시하는 요소를 기반으로 데이터를 그룹화하여 페이지 매김에 버킷 패턴을 사용할 수 있습니다. 이 접근 방식은 MongoDB의 유연한 데이터 모델을 사용하여 애플리케이션에 필요한 데이터에 따라 데이터를 저장합니다.
팁
시계열 컬렉션 은 버킷 패턴 을 자동으로 적용 하며, Time Series 데이터 를 버킷화하는 대부분의 애플리케이션에 적합합니다.
이 작업에 대하여
주식 거래를 추적하는 다음 스키마를 가정해 보겠습니다. 초기 스키마는 버킷 패턴을 사용하지 않고 각 거래를 개별 문서에 저장합니다.
db.trades.insertMany( [ { "ticker" : "MDB", "customerId": 123, "type" : "buy", "quantity" : 419, "date" : ISODate("2023-10-26T15:47:03.434Z") }, { "ticker" : "MDB", "customerId": 123, "type" : "sell", "quantity" : 29, "date" : ISODate("2023-10-30T09:32:57.765Z") }, { "ticker" : "GOOG", "customerId": 456, "type" : "buy", "quantity" : 50, "date" : ISODate("2023-10-31T11:16:02.120Z") } ] )
이 애플리케이션은 한 번에 한 고객이 수행한 주식 거래를 표시하며 페이지당 10개의 거래를 표시합니다. 애플리케이션 로직을 단순화하려면 버킷 패턴을 사용하여 customerId
별로 10개 그룹으로 거래를 그룹화합니다.
단계
customerId별로 데이터 그룹화
각 customerId
에 대해 단일 문서를 갖도록 스키마를 재구성합니다.
{ "customerId": 123, "history": [ { "type": "buy", "ticker": "MDB", "qty": 419, "date": ISODate("2023-10-26T15:47:03.434Z") }, { "type": "sell", "ticker": "MDB", "qty": 29, "date": ISODate("2023-10-30T09:32:57.765Z") } ] }, { "customerId": 456, "history": [ { "type" : "buy", "ticker" : "GOOG", "quantity" : 50, "date" : ISODate("2023-10-31T11:16:02.120Z") } ] }
버킷 패턴을 사용하면 다음이 가능합니다.
일반적인
customerId
값을 가진 문서는 단일 문서로 압축되며customerId
는 최상위 필드입니다.해당 고객에 대한 거래는
history
라는 내장된 배열 필드로 그룹화됩니다.
각 버킷의 식별자 및 개수 추가
1 db.trades.drop() 2 3 db.trades.insertMany( 4 [ 5 { 6 "_id": "123_1698349623", 7 "customerId": 123, 8 "count": 2, 9 "history": [ 10 { 11 "type": "buy", 12 "ticker": "MDB", 13 "qty": 419, 14 "date": ISODate("2023-10-26T15:47:03.434Z") 15 }, 16 { 17 "type": "sell", 18 "ticker": "MDB", 19 "qty": 29, 20 "date": ISODate("2023-10-30T09:32:57.765Z") 21 } 22 ] 23 }, 24 { 25 "_id": "456_1698765362", 26 "customerId": 456, 27 "count": 1, 28 "history": [ 29 { 30 "type" : "buy", 31 "ticker" : "GOOG", 32 "quantity" : 50, 33 "date" : ISODate("2023-10-31T11:16:02.120Z") 34 } 35 ] 36 }, 37 ] 38 )
_id
필드 값은 customerId
와 history
필드의 첫 번째 거래 시간(유닉스 시간 이후)을 초 단위로 연결한 것입니다.
count
필드 는 해당 문서의 history
배열 에 있는 요소의 수를 나타냅니다. count
필드 는 페이지 매김 로직을 구현 하는 데 사용됩니다.
다음 단계
버킷 패턴을 사용하도록 스키마를 업데이트한 후에는 데이터 읽기 및 쓰기를 위한 애플리케이션 로직을 업데이트하세요. 다음 섹션을 참조하세요.
Bucket 패턴으로 데이터 쿼리하기
업데이트된 스키마에서 각 문서에는 애플리케이션의 단일 페이지에 대한 데이터가 포함됩니다. _id
및 count
필드를 사용하여 데이터를 반환하고 업데이트하는 방법을 결정할 수 있습니다.
해당 페이지의 데이터를 쿼리하려면 정규식 쿼리를 사용하여 지정된 customerId
에 대한 데이터를 반환하고, skip
을(를) 사용하여 올바른 페이지에 대한 데이터로 반환합니다. _id
에 대한 정규식 쿼리는 default _id index를 사용하므로 추가 인덱스 없이도 성능이 우수한 쿼리를 생성합니다.
다음 쿼리는 고객 123
의 첫 번째 거래 페이지에 대한 데이터를 반환합니다.
db.trades.find( { "_id": /^123_/ } ).sort( { _id: 1 } ).limit(1)
이후 페이지에 대한 데이터를 반환하려면 데이터를 표시하려는 페이지보다 1이 적은 skip
값을 지정합니다. 예를 들어 10페이지에 대한 데이터를 표시하려면 다음 쿼리를 실행합니다.
db.trades.find( { "_id": /^123_/ } ).sort( { _id: 1 } ).skip(9).limit(1)
참고
샘플 데이터에 첫 페이지에 대한 문서만 포함되어 있기 때문에 이전의 쿼리는 결과가 반환되지 않습니다.
버킷 패턴으로 데이터 삽입하기
이제 스키마가 버킷 패턴을 사용하므로 애플리케이션 로직을 업데이트하여 새 거래를 올바른 버킷에 삽입합니다. 적절한 customerId
및 버킷을 사용해 거래를 버킷에 삽입하려면 업데이트 명령을 사용합니다.
다음 명령은 customerId: 123
에 대한 새로운 거래를 삽입합니다.
db.trades.updateOne( { "_id": /^123_/, "count": { $lt: 10 } }, { "$push": { "history": { "type": "buy", "ticker": "MSFT", "qty": 42, "date": ISODate("2023-11-02T11:43:10") } }, "$inc": { "count": 1 }, "$setOnInsert": { "_id": "123_1698939791", "customerId": 123 } }, { upsert: true } )
애플리케이션 은 페이지당 10 개의 거래를 표시합니다. 업데이트 필터하다 는 count
가 10 보다 작은 customerId: 123
에 대한 문서 를 검색하며, 이는 버킷에 전체 데이터 페이지가 포함되어 있지 않음을 의미합니다.
"_id": /^123_/
와 일치하는 문서 가 있고 해당 문서의count
이 10 보다 작은 경우, 업데이트 명령은 새 거래를 일치하는 문서의history
배열 로 푸시합니다.일치하는 문서 가 없는 경우 업데이트 명령은 새 거래로 새 문서 를 삽입합니다(
upsert
이true
이므로). 새 문서 의_id
필드 는customerId
와 거래의 유닉스 시간 시간 이후의 시간(초)을 연결한 것입니다.
업데이트 명령 로직은 history
배열에 10개 이상의 문서가 포함되지 않도록 하여 무제한 배열을 방지합니다.
업데이트 작업을 실행하면 trades
컬렉션에 다음 문서가 포함됩니다.
[ { _id: '123_1698349623', customerId: 123, count: 3, history: [ { type: 'buy', ticker: 'MDB', qty: 419, date: ISODate("2023-10-26T15:47:03.434Z") }, { type: 'sell', ticker: 'MDB', qty: 29, date: ISODate("2023-10-30T09:32:57.765Z") }, { type: 'buy', ticker: 'MSFT', qty: 42, date: ISODate("2023-11-02T11:43:10.000Z") } ] }, { _id: '456_1698765362', customerId: 456, count: 1, history: [ { type: 'buy', ticker: 'GOOG', quantity: 50, date: ISODate("2023-10-31T11:16:02.120Z") } ] } ]
결과
버킷 패턴 을 구현 한 후에는 애플리케이션 에 결과를 반환하기 위해 페이지 매김 로직을 통합할 필요가 없습니다. 데이터가 저장되는 방식은 애플리케이션 에서 데이터가 사용되는 방식과 일치합니다.