MongoDB — 埋め込みと実行計画
目標
Pod内で動く本物のMongoDB 8.0の上で、ドキュメントを挿入し、検索し、インデックスを張り、集計し、スキーマを設定し、埋め込みを試します。最後に実行計画を読んで、数字で書き残します。
接続
mongosh labdb
labdbを使います。PostgreSQLも同じPodで動いているので、psqlもそのまま使えます。2つのデータベースを並べて、同じ問題をそれぞれ解いてみると、違いがはるかにはっきりします。
結果ファイル
いくつかのステップは、結果をファイルに残します。先にmkdir -p /root/work/mongoを実行してください。シェルでJSONを保存するときは、次のように書きます。
mongosh --quiet labdb --eval 'JSON.stringify(db.items.find({},{_id:0}).toArray())' > /root/work/mongo/02-query.json
ドキュメントを挿入する(値が配列のこともある)
mongosh labdbで接続します。db.items.insertMany([...])で5件以上を挿入してください。各ドキュメントにname(文字列)、qty(数値)、tags(配列)を持たせてください。1つは名前が빨간 배낭である必要があります(このコードは、韓国語で「赤いバックパック」を意味する語です)。
itemsに5件以上あり、各ドキュメントにname・qty・tags(配列)があります。
必要なフィールドだけを取得する
qtyが0より大きいドキュメントを探し、nameとqtyだけを射影してください(_id: 0)。結果を/root/work/mongo/02-query.jsonにJSON配列として保存します。mongosh --quiet --evalとJSON.stringifyを使うと便利です。
02-query.jsonに、qty>0のドキュメントがnameとqtyだけを持つ形で入っています。
インデックスを作成し、実行計画が変わるか確認する
db.items.createIndex({name: 1})を実行します。そのあと、db.items.find({name:'빨간 배낭'}).explain()で、実行計画にIXSCANが出るか確認してください(コード内の文字列は、韓国語で「赤いバックパック」を意味する語です)。
nameのインデックスがあり、そのクエリがIXSCANを使っています。
1つのフィールドだけを変更する
빨간 배낭のqtyを10に変更してください(最初のコードは、韓国語で「赤いバックパック」を意味する語です)。$setを使ってください。ドキュメントを丸ごと代入すると、書かなかったフィールドが消えます。
qtyは10で、nameとtagsはそのまま残っています。
配列を展開してタグ別にまとめる
$unwindでtagsを展開し、$groupでタグ別のqtyの合計を求めてください。結果を/root/work/mongo/05-bytag.jsonに[{_id, total}, ...]の形で保存します。
05-bytag.jsonのタグ別の合計が、実際の値と一致しています。
ドキュメントDBにもスキーマを設定する
db.createCollection('orders', {validator: {$jsonSchema: {...}}})で、qtyを必須かつ数値に定めてください。ルールを書いておいても、実際に弾かれなければ、ないのと同じです。文字列を入れて拒否されるか、自分で試してください。
ordersに$jsonSchemaの検証があり、誤った型が実際に拒否されます。
一緒に読まれるものは埋め込む
ordersに注文を1件入れ、明細をlines配列として埋め込んでください(2件以上、各項目にnameとqty)。ステップ6の検証を通過するように、qtyも一緒に入れてください。db.orders.find({'lines.name': ...})で配列の中を検索できます。
注文ドキュメント1件にlinesが2件以上あり、lines.nameで検索できます。
実行計画を読み、数字で書き残す
/root/work/mongo/08-explain.txtに、インデックスがあるとき(IXSCAN)とないとき(COLLSCAN)を比較して書いてください。explain('executionStats')のtotalDocsExaminedのような数字を必ず含めてください。
08-explain.txtにIXSCAN・COLLSCANと数字が一緒に書かれています。