Docs Menu
Docs Home
/
MongoDBマニュアル
/ / /

バケット パターンでデータをグループ化する

項目一覧

  • このタスクについて
  • 手順
  • データを customerId でグループ化
  • 各バケットの識別子とカウントの追加
  • 次のステップ
  • バケット パターンを含むデータのクエリ
  • バケット パターンを使用したデータの挿入
  • 結果
  • 詳細

バケット パターンは、長い一連のデータを個別のオブジェクトに分割します。 大規模なデータ系列を小さなグループに分離すると、クエリ アクセス パターンが改善され、アプリケーション ロジックが簡素化されます。 バケットは、単一のユーザーによって行われる株式トランザクションなど、中央エンティティに関連する同様のオブジェクトがある場合に便利です。

アプリケーションがページごとに表示する要素に基づいてデータをグループ化することで、バケット パターンをページ分割に使用できます。 このアプローチでは、MongoDB の柔軟なデータモデルを使用して、アプリケーションが必要とするデータに応じてデータを保存します。

Tip

時系列コレクションはバケット パターンを自動的に適用するため、時系列データのバケット化に関与するほとんどのアプリケーションに適しています。

株式のトランザクションを追跡する次のスキーマを考慮します。 最初のスキーマではバケット パターンは使用されず、各トランザクションが個別のドキュメントに保存されます。

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")
}
]
)

このアプリケーションには、1 人のカスタマーが一度に行った株式トランザクションが表示され、1 ページあたり 10 件のトランザクションが表示されます。 アプリケーション ロジックを簡素化するために、バケット パターンを使用してトランザクションを 10 のグループでグループcustomerId

1

customerIdに対して 1 つのドキュメントを含むようにスキーマを再構成します。

{
"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値を持つドキュメントは 1 つのドキュメントに凝縮され、 customerIdは最上位フィールドになります。

  • そのカスタマーのトランザクションは、 historyと呼ばれる埋め込み配列フィールドにグループ化されます。

2
1db.trades.drop()
2
3db.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フィールド値は、 customerIdhistoryフィールドの秒単位の最初のトランザクション時間( UNIX エポック以降)を連結したものです。

countフィールドは、そのドキュメントのhistory配列にある要素の数を示します。 countフィールドは、ページ分割ロジックを実装するために使用されます。

バケット パターンを使用するようにスキーマを更新したら、データの読み取りと書き込みのアプリケーション ロジックを更新します。 次のセクションを参照してください。

  • バケット パターンを含むデータのクエリ

  • バケット パターンを使用したデータの挿入

更新されたスキーマでは、各ドキュメントにアプリケーション内の 1 つのページのデータが含まれています。 _idcountデータを返して更新する方法を決定するには、 フィールドと フィールドを使用します。

適切なページのデータをクエリするには、正規表現クエリを使用して指定されたcustomerIdのデータを返し、 skipを使用して正しいページのデータを返します。 _idの正規表現クエリはデフォルトの _id インデックスを使用するため、追加のインデックスは必要ありません。

次のクエリは、カスタマー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 }
)

アプリケーションには、1 ページあたり10のトランザクションが表示されます。 アップデート フィルターは、 countが10より小さいcustomerId: 123のドキュメントを検索します。つまり、バケットには完全なページのデータが含まれていません。

  • "_id": /^123_/に一致するドキュメントがあり、そのcountが10より小さい場合、アップデート コマンドは新しいトランザクションを一致したドキュメントのhistory配列にプッシュします。

  • 一致するドキュメントがない場合、アップデート コマンドは新しいトランザクションを含む新しいドキュメントを挿入します( upserttrueであるため)。 新しいドキュメントの_idフィールドは、 customerIdとトランザクションの UNIX エポックからの時間(秒単位)を連結したものです。

アップデート コマンドのロジックは、 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")
}
]
}
]

バケット パターンを実装した後、アプリケーションで結果を返すためにページ分割ロジックを組み込む必要はありません。 データの保存方法は、アプリケーションでの使用方法と一致します。

戻る

グループデータ