MongoDBのCRUD(Create, Read, Update, Delete)操作についてまとめます。
前提
公式ドキュメント
参考になる公式ドキュメントを以下に示します。
動作確認済環境
- Rocky Linux 8.6
- MongoDB Server 6.0.2
公式ドキュメントの読み方
CRUD操作はツール毎に使用感が異なります。本書はmongosh(MongoDB shell)を使う場合を示しますが、公式ドキュメントではMongoDB shell, Compass(GUIツール), C#, Go, Java(Async), Java(Sync), Motor, Node.jsの操作例が示されています。
公式ドキュメント右上の「Select your language」プルダウンを操作する事で、お好みのツールの使用方法を調査する事ができます。
img 001
CRUD操作
Create
1件Create
1件Createの操作をするには、InsertOneを使用します。操作例は以下の通りです。
db.createCollection('inventory') db.inventory.insertOne( { _id: 0, item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } } )
想定通りのレコードが追加された事を確認します。
test> db.inventory.find() [ { _id: 0, item: 'canvas', qty: 100, tags: [ 'cotton' ], size: { h: 28, w: 35.5, uom: 'cm' } } ]
複数件Create
複数件Createの操作をするには、InsertManyを使用します。操作例は以下の通りです。
InsertManyで登録されたデータは原子性(Atomicity)が保証されます。
db.inventory.insertMany([ { _id: 1, item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } }, { _id: 2, item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } }, ])
想定通りのレコードが追加された事を確認します。
test> db.inventory.find() [ { _id: 0, item: 'canvas', qty: 100, tags: [ 'cotton' ], size: { h: 28, w: 35.5, uom: 'cm' } }, { _id: 1, item: 'journal', qty: 25, tags: [ 'blank', 'red' ], size: { h: 14, w: 21, uom: 'cm' } }, { _id: 2, item: 'mat', qty: 85, tags: [ 'gray' ], size: { h: 27.9, w: 35.5, uom: 'cm' } } ] test>
PrimaryKey(_id)省略時の挙動
insert処理をする時はPrimaryKey(_id)を省略する事もできます。PrimaryKey(_id)を省略した場合は、ObjectIDがPrimaryKey(_id)にセットされます。
以下に操作例を示します。確かに、PrimaryKey(_id)がObjectIDとなる事を確認できます。
test> db.inventory.insertOne( ... { item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } } ... ) { acknowledged: true, insertedId: ObjectId("634d3bbb05cb7e4fd9c0fee9") } test> db.inventory.find( { item: "mousepad" } ) [ { _id: ObjectId("634d3bbb05cb7e4fd9c0fee9"), item: 'mousepad', qty: 25, tags: [ 'gel', 'blue' ], size: { h: 19, w: 22.85, uom: 'cm' } } ] test>
Read
データ準備
動作確認用のデータを準備します。
db.inventory.drop() db.createCollection('inventory') db.inventory.insertMany([ { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" }, { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" }, { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" }, { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" }, { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" } ]);
全件検索
全件検索するには以下のような操作をします。
db.inventory.find()
条件指定検索
条件指定で検索する場合は、findの引数に検索条件を与えます。書式は以下の通りです。
db.inventory.find({ <field1>: <value1>, ... })
単純な完全一致検索ならば、以下のように操作します。
db.inventory.find( { status: "D" } )
大小比較ならば、以下のように操作します。
db.inventory.find( { qty: { $lt: 50 } } )
含まれるかどうかの操作(SQL文のIN句)ならば、以下のように操作します。
db.inventory.find( { status: { $in: [ "A", "D" ] } } )
AND条件
複数条件を使用しAND条件で検索したい場合は、以下のように操作します。
db.inventory.find( { status: "A", qty: { $lt: 30 } } )
OR条件
複数条件を使用しOR条件で検索したい場合は、以下のように操作します。
db.inventory.find( { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] } )
AND条件とOR条件を併用する場合は、以下のように操作します。
db.inventory.find( { status: "A", $or: [ { qty: { $lt: 30 } }, { item: /^p/ } ] } )
表示フィールドの絞り込み
全てのフィールドが表示されるのがわずらわしく、一部フィールドのみを表示したい事もあるかもしれません。そのような場合は、SQL文のSELECT句相当の操作もできます。findメソッドに以下のような引数を与えます。
find({<検索条件1>}, {<検索条件2>}, ... {<表示条件>})
statusがAのレコードについてitem, qtyのみを表示させるならば、以下のように操作します。1またはtrueを指定したフィールドが表示対象になり、0またはfalseを指定したフィールドが非表示になります。_idはデフォルトで表示されますので、もし_idを非表示にしたいならば「_id: 0」と指定します。
test> db.inventory.find( {status: "A"}, { item: 1, qty: 1, _id: 0 } ) [ { item: 'journal', qty: 25 }, { item: 'notebook', qty: 50 }, { item: 'postcard', qty: 45 } ] test>
全件についてitem, qtyのみを表示させるならば、以下のように操作します。
test> db.inventory.find( {}, { item: 1, qty: 1, _id: 0 } ) [ { item: 'journal', qty: 25 }, { item: 'notebook', qty: 50 }, { item: 'paper', qty: 100 }, { item: 'planner', qty: 75 }, { item: 'postcard', qty: 45 } ] test>
Update
データ準備
動作確認用のデータを準備します。
db.inventory.drop() db.createCollection('inventory') db.inventory.insertMany( [ { item: "canvas", qty: 100, size: { h: 28, w: 35.5, uom: "cm" }, status: "A" }, { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" }, { item: "mat", qty: 85, size: { h: 27.9, w: 35.5, uom: "cm" }, status: "A" }, { item: "mousepad", qty: 25, size: { h: 19, w: 22.85, uom: "cm" }, status: "P" }, { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "P" }, { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" }, { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" }, { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }, { item: "sketchbook", qty: 80, size: { h: 14, w: 21, uom: "cm" }, status: "A" }, { item: "sketch pad", qty: 95, size: { h: 22.85, w: 30.5, uom: "cm" }, status: "A" } ] );
1件Update
MongoDBでレコードを更新するには、updateOne, updateMany, replaceOneなどのメソッドを使います。 これらメソッドに与える引数は以下のように指定します。update operatorには更新対象を絞り込む条件(WHRER句相当)を記述します。
{ <update operator>: { <field1>: <value1>, ... }, <update operator>: { <field2>: <value2>, ... }, ... }
canvasを変更する操作を例示します。まずは、変更前のレコードを確認します。変更前は数量(qty)は100で最終更新時刻も記録されていません。
test> db.inventory.find({item: "canvas"}) [ { _id: ObjectId("635102fd692a7c235c919914"), item: 'canvas', qty: 100, size: { h: 28, w: 35.5, uom: 'cm' }, status: 'A' } ] test>
canvasの数量(qty)を40に変更し最終更新時刻を付与する操作をします。
db.inventory.updateOne( { item: "canvas" }, { $set: { qty: 40 }, $currentDate: { lastModified: true } } )
数量(qty)が40に変わり最終更新時刻が付与された事を確認できます。
test> db.inventory.find({item: "canvas"}) [ { _id: ObjectId("635102fd692a7c235c919914"), item: 'canvas', qty: 40, size: { h: 28, w: 35.5, uom: 'cm' }, status: 'A', lastModified: ISODate("2022-10-20T08:31:50.795Z") } ] test>
複数件Update
数量(qty)が30未満の商品について、一括で変更する操作をします。まずは、変更前のレコードを確認します。変更前は単位(size.uom)をセンチ(cm)で、statusはAとPが混在しています。
test> db.inventory.find({qty: { $lt: 30 } }) [ { _id: ObjectId("635102fd692a7c235c919915"), item: 'journal', qty: 25, size: { h: 14, w: 21, uom: 'cm' }, status: 'A' }, { _id: ObjectId("635102fd692a7c235c919917"), item: 'mousepad', qty: 25, size: { h: 19, w: 22.85, uom: 'cm' }, status: 'P' } ] test>
数量(qty)が30未満の商品について、単位(size.uom)をセンチ(cm)からインチ(in)に変更しstatusをPに変更する操作をします。
db.inventory.updateMany( { "qty": { $lt: 30 } }, { $set: { "size.uom": "in", status: "P" } } )
想定通りの変更がなされた事を確認します。
test> db.inventory.find({qty: { $lt: 30 } }) [ { _id: ObjectId("635102fd692a7c235c919915"), item: 'journal', qty: 25, size: { h: 14, w: 21, uom: 'in' }, status: 'P' }, { _id: ObjectId("635102fd692a7c235c919917"), item: 'mousepad', qty: 25, size: { h: 19, w: 22.85, uom: 'in' }, status: 'P' } ] test>
1件Replace
前述のupdateメソッドは指定したフィールドのみが更新される操作です。これに対し、replaceメソッドは全てのフィールドが更新される操作です。言い換えれば、指定していないフィールドは削除されます。それでは実際の例を観察してみましょう。
変更前のpaperは以下のような状態です。変更前はsizeフィールドとstatusフィールドが存在する事を覚えていてください。
test> db.inventory.find({item: "paper"}) [ { _id: ObjectId("635102fd692a7c235c919919"), item: 'paper', qty: 100, size: { h: 8.5, w: 11, uom: 'in' }, status: 'D' } ] test>
paperをreplaceします。
db.inventory.replaceOne( { item: "paper" }, { item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 40 } ] } )
変更後のpaperを以下に示します。replaceOneメソッドにsizeフィールドやstatusは含まれていないため、更新後はsizeフィールドが消えている事が読み取れます。代わりに、replaceOneメソッドで指定したinstockフィールドが追加されている事も読み取れます。
test> db.inventory.find({item: "paper"}) [ { _id: ObjectId("635102fd692a7c235c919919"), item: 'paper', instock: [ { warehouse: 'A', qty: 60 }, { warehouse: 'B', qty: 40 } ] } ] test>
Delete
データ準備
動作確認用のデータを準備します。
db.inventory.drop() db.createCollection('inventory') db.inventory.insertMany( [ { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" }, { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "P" }, { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" }, { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" }, { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }, ] );
1件Delete
notebookを削除する操作例を示します。それでは変更前の全件を確認します。変更前はnotebookが存在します。
test> db.inventory.find( {}, { item: 1, qty: 1, _id: 0 } ) [ { item: 'journal', qty: 25 }, { item: 'notebook', qty: 50 }, { item: 'paper', qty: 100 }, { item: 'planner', qty: 75 }, { item: 'postcard', qty: 45 } ] test>
notebookを削除します。
db.inventory.deleteOne( { item: 'notebook' } )
notebookが削除された事を確認します。
test> db.inventory.find( {}, { item: 1, qty: 1, _id: 0 } ) [ { item: 'journal', qty: 25 }, { item: 'paper', qty: 100 }, { item: 'planner', qty: 75 }, { item: 'postcard', qty: 45 } ] test>
複数件Delete
数量(qty)が50件未満のレコードを削除する操作例を示します。それでは変更前の全件を確認します。変更前はjournalとpostcardが存在します。
test> db.inventory.find( {}, { item: 1, qty: 1, _id: 0 } ) [ { item: 'journal', qty: 25 }, { item: 'paper', qty: 100 }, { item: 'planner', qty: 75 }, { item: 'postcard', qty: 45 } ] test>
数量(qty)が50件未満のレコードを削除します。
db.inventory.deleteMany( {qty: { $lt: 50 } } )
journalとpostcardが削除された事を確認します。
test> db.inventory.find( {}, { item: 1, qty: 1, _id: 0 } ) [ { item: 'paper', qty: 100 }, { item: 'planner', qty: 75 } ] test>
フィールド削除
レコードそのものではなく、レコードの1つのフィールドを削除するには前述のreplaceOneを使うと良いでしょう。
繰り返しになりますが、再度の動作確認をします。変更前のpaperの状態を確認します。sizeやstatusのフィールドが存在します。
test> db.inventory.find( {item: "paper"} ) [ { _id: ObjectId("63510cb0692a7c235c919920"), item: 'paper', qty: 100, size: { h: 8.5, w: 11, uom: 'in' }, status: 'D' } ] test>
size, statusのフィールドを削除します。
db.inventory.replaceOne( { item: "paper" }, { item: "paper", qty: 100 } )
想定通りのフィールド削除がなされて事を確認します。
test> db.inventory.find( {item: "paper"} ) [ { _id: ObjectId("63510cb0692a7c235c919920"), item: 'paper', qty: 100 } ] test>