ひとりMongoDB University 12/01

5 min read読了の目安(約5100字

はじめに

この記録は、MongoDB Universityの学習コースの記録です。
引き続き、M001のコースです。12/15までに終わらせるのを目標にしています。
詳細はこちら。

ひとまず継続して日記的に記録をしていきます。

Chapter 5: Indexing and Aggregation Pipeline

まずはアグリゲーション

これは MQLのfindと同じように基本は検索できるけれど、その処理を「パイプライン」としてつなげて実行できるもの!
検索 -> フィルタ(プロジェクション)-> 加工といった感じで、配列に処理を指定して実行できる。

  • db.コレクション名.aggregate9[.... 処理内容の配列 ...] という指定

db.listingsAndReviews.find({ "amenities": "Wifi" },
  { "price": 1, "address": 1, "_id": 0 }).pretty().count()
# 5303件

# 1件だけfindからピックアップ
db.listingsAndReviews.find({ "amenities": "Wifi" },
  { "price": 1, "address": 1, "_id": 0 }).pretty().limit(1)
{ price: Decimal128({"$numberDecimal":"40.00"}),
  address:
   { street: 'Brooklyn, NY, United States',
     suburb: 'Brooklyn',
     government_area: 'Bushwick',
     market: 'New York',
     country: 'United States',
     country_code: 'US',
     location:
      { type: 'Point',
        coordinates: [ -73.93615, 40.69791 ],
        is_location_exact: true } } }

# この場合は、配列の1つめで条件に合うドキュメントを抽出
# 配列の2つめでドキュメントから全てのkey & valueでなく、project(射影)したセットだけを取り出す
db.listingsAndReviews.aggregate([
  { "$match": { "amenities": "Wifi" } },
  { "$project": { "price": 1, "address": 1, "_id": 0 } }
]).pretty()

db.listingsAndReviews.aggregate([
  { "$match": { "amenities": "Wifi" } },
  { "$project": { "price": 1, "address": 1, "_id": 0 }}]).pretty()

# 抽出結果 (配列で返る)
[
  ....,
  { price:
     { _bsontype: 'Decimal128',
       bytes: <Buffer a0 0f 00 00 00 00 00 00 00 00 00 00 00 00 3c 30> },
    address:
     { street: 'Porto, Porto, Portugal',
       suburb: '',
       government_area: 'Cedofeita, Ildefonso, Sé, Miragaia, Nicolau, Vitória',
       market: 'Porto',
       country: 'Portugal',
       country_code: 'PT',
       location:
        { type: 'Point',
          coordinates: [ -8.60867, 41.1543 ],
          is_location_exact: false } } }
]

# 上記の程度であればMQLだけでも同じ様には取れる
db.listingsAndReviews.findOne({ },{ "address": 1, "_id": 0 })
{ address:
   { street: 'Brooklyn, NY, United States',
     suburb: 'Brooklyn',
     government_area: 'Bushwick',
     market: 'New York',
     country: 'United States',
     country_code: 'US',
     location:
      { type: 'Point',
        coordinates: [ -73.93615, 40.69791 ],
        is_location_exact: true } } }

Why Aggregation? / アグリゲーションの何が良いの?

  • MQLは、ドキュメントの「検索(絞り込み)」と「更新」を主に担当
  • Aggregationは、抽出したデータの整形や加工、演算処理に適している

もっと実践的なアグリゲーション (Aggregation) のコースは、M121になります。

Aggregationでの集計など


# この場合は、まず抽出列を絞り込み、addressデータ(さらに内部で配列)に対し
# countryの条件でグルーピング
db.listingsAndReviews.aggregate([ { "$project": { "address": 1, "_id": 0 }},
  { "$group": { "_id": "$address.country" }}])

# こんな結果が返る
[ { _id: 'Canada' },
  { _id: 'Australia' },
  { _id: 'China' },
  { _id: 'United States' },
  { _id: 'Portugal' },
  { _id: 'Turkey' },
  { _id: 'Spain' },
  { _id: 'Brazil' },
  { _id: 'Hong Kong' } ]

# 上記ではグルーピングしただけなので、さらにCountry単位での集計を実施
# "count" は表示させる際の「キー」として利用
# 対応する値は、$sum で実施
db.listingsAndReviews.aggregate([
  { "$project": { "address": 1, "_id": 0 }},
  { "$group": { "_id": "$address.country",
    "count": { "$sum": 1 } } }
])

[ { _id: 'Canada', count: 649 },
  { _id: 'China', count: 19 },
  { _id: 'Brazil', count: 606 },
  { _id: 'Hong Kong', count: 600 },
  { _id: 'Australia', count: 610 },
  { _id: 'Portugal', count: 555 },
  { _id: 'Turkey', count: 661 },
  { _id: 'Spain', count: 633 },
  { _id: 'United States', count: 1222 } ]

Lab: Aggregation Framework (演習問題)

Q. What room types are present in the sample_airbnb.listingsAndReviews collection?
(sample_airbnb.listingsAndReviewsコレクションで、どんな対応の部屋がありますか?)

A. 考え方

  • グルーピングすればいいかな?

# まずはキーを確認
# room_type で良さそう
db.listingsAndReviews.findOne({ },{ "room_type": 1, "_id": 0 })
{ room_type: 'Private room' }

# room_typeのみ抽出 -> group でまとめる
db.listingsAndReviews.aggregate([
  { "$project": { "room_type": 1, "_id": 0 } },
  { "$group": { "_id": "$room_type" } }
])

# 結果 -> これで正解!
[ { _id: 'Shared room' },
  { _id: 'Private room' },
  { _id: 'Entire home/apt' } ]

Q. What are the differences between using aggregate() and find()?
(aggregateとfindの違いは?)

A. こんな感じ

  • aggregate() can do what find() can and more.
    • findでできること+アルファのことができるよ!
  • aggregate() allows us to compute and reshape data in the cursor.
    • カーソルを用いて順にデータを計算したり整形したりできるよ!

本日の記録

動画1つと問題2つ進みました

きょうのzenn

コマンドを実行しようとしたら、アップデートしてね!のメッセージが。

   ╭─────────────────────────────────────────────────────╮
   │                                                     │
   │       CLIに変更があります 0.1.58 → 0.1.59 💡           │
   │   `npm install zenn-cli@latest`で更新してください      │
   │                                                     │
   ╰─────────────────────────────────────────────────────╯

zenn-contents $ npm install zenn-cli@latest

zenn-contents $ npx zenn new:article --slug 20201201-mongodb-univ
📄20201201-mongodb-univ.md created.

記事はslugを付けて作成しました。
また次も書けるかな。