😹

MongoDBを操作してみる

2022/10/20に公開約5,500字

背景

今更ながらMongoDBを再学習中です。
今回は、コマンドラインからMongoDBを操作してみます。

操作

データの追加と参照

ドキュメントusers{username:"hashito"}を追加してみます。

test> db.users.insert({username:"hashito"})
DeprecationWarning: Collection.insert() is deprecated. Use insertOne, insertMany, or bulkWrite.
{
  acknowledged: true,
  insertedIds: { '0': ObjectId("63509ddb39e7cde9bce5f310") }
}

MongoDBではアクセスした瞬間にドキュメントが生成されるようです。
基本的な方法で、データを参照してみます。

また、insertは非推奨になっていることがわかります。
insertOneinsertManybulkWriteの利用を推奨されています。

https://stackoverflow.com/questions/36792649/whats-the-difference-between-insert-insertone-and-insertmany-method

こちらの記載通り1件追加の場合はinsertOneを利用し、複数個の場合はinsertManybulkWriteを利用すれば問題ないものと思われます。

test> db.users.find()
[ { _id: ObjectId("63509ddb39e7cde9bce5f310"), username: 'hashito' } ]

.find()は引数を利用することでフィルタリングなどもあるようですが、一旦は引数無しで利用します。
ドキュメントusersの中にはデータが1つしかないことがわかります。

ドキュメントのデータ数をカウントしてみます。
db.users.count()という関数を利用します。

test> db.users.count()
DeprecationWarning: Collection.count() is deprecated. Use countDocuments or estimatedDocumentCount.
1

countという関数は非推奨であるためcountDocumentsestimatedDocumentCountを利用するように言われます。

2つを要望していますがどちらがいいという議論はあるようです…
https://stackoverflow.com/questions/53542003/how-accurate-is-mongodbs-estimated-count-query

test> db.users.countDocuments()
1
test> db.users.estimatedDocumentCount()
1

データを追加して結果を再確認してみます。

test> db.users.insert({username:"hashito2"})
{
  acknowledged: true,
  insertedIds: { '0': ObjectId("6350a7a139e7cde9bce5f311") }
}
test> db.users.estimatedDocumentCount()
2
test> db.users.countDocuments()
2
test> db.users.find()
[
  { _id: ObjectId("63509ddb39e7cde9bce5f310"), username: 'hashito' },
  { _id: ObjectId("6350a7a139e7cde9bce5f311"), username: 'hashito2' }
]

データのフィルタリング

.find関数で引数を指定する事により、特定のusernameを持っているデータのみにフィルタリングする事ができます。

test> db.users.find({username:"hashito"})
[ { _id: ObjectId("63509ddb39e7cde9bce5f310"), username: 'hashito' } ]

hashito2という名前のユーザは検索されない事がわかります。

データの更新

update関数を利用することでデータを更新する事ができます。

test> db.users.update({username:"hashito"},{$set:{city:"tokyo"}})
DeprecationWarning: Collection.update() is deprecated. Use updateOne, updateMany, or bulkWrite.
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
test> db.users.find({username:"hashito"})
[
  {
    _id: ObjectId("63509ddb39e7cde9bce5f310"),
    username: 'hashito',
    city: 'tokyo'
  }
]

こちらのupdate関数も同様に非推奨ですね…(私が参考にしている本が古いため申し訳ないです。)
アップデートする対象が1件の場合はupdateOneで複数個の場合は updateMany bulkWriteのいづれかを利用してください。

値の削除を行う場合もupdate系の関数を利用します。

test> db.users.updateOne({username:"hashito"},{$unset:{city:1}})
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
test> db.users.find({username:"hashito"})
[ { _id: ObjectId("63509ddb39e7cde9bce5f310"), username: 'hashito' } ]

少し高度な検索

少し高度な検索を行うため、要素を追加します。
f.movies["a","b"]または["x","b"]を追加しています。

test> db.users.update({username:"hashito"},{$set:{f:{movies:["a","b"]}}})
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
test> db.users.update({username:"hashito2"},{$set:{f:{movies:["x","b"]}}})
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
test> db.users.find()
[
  {
    _id: ObjectId("63509ddb39e7cde9bce5f310"),
    username: 'hashito',
    f: { movies: [ 'a', 'b' ] }
  },
  {
    _id: ObjectId("6350a7a139e7cde9bce5f311"),
    username: 'hashito2',
    f: { movies: [ 'x', 'b' ] }
  }
]

この中で、f.movies.bのみを持っているデータを抽出します。

test> db.users.find({"f.movies":"b"})
[
  {
    _id: ObjectId("63509ddb39e7cde9bce5f310"),
    username: 'hashito',
    f: { movies: [ 'a', 'b' ] }
  },
  {
    _id: ObjectId("6350a7a139e7cde9bce5f311"),
    username: 'hashito2',
    f: { movies: [ 'x', 'b' ] }
  }
]

この中で、f.movies.xのみを持っているデータを抽出します。

test> db.users.find({"f.movies":"x"})
[
  {
    _id: ObjectId("6350a7a139e7cde9bce5f311"),
    username: 'hashito2',
    f: { movies: [ 'x', 'b' ] }
  }
]

データの削除

remove関数を利用すればデータの削除をできます。
このときにfindと同じ形式でフィルタリングする事が可能です。

test> db.users.remove({"f.movies":"x"})
DeprecationWarning: Collection.remove() is deprecated. Use deleteOne, deleteMany, findOneAndDelete, or bulkWrite.
{ acknowledged: true, deletedCount: 1 }

test> db.users.find()
[
  {
    _id: ObjectId("63509ddb39e7cde9bce5f310"),
    username: 'hashito',
    f: { movies: [ 'a', 'b' ] }
  }
]

findの結果を見れば削除が成功している事がわかります。

こちらもremove関数は非推奨のようです…
アップデートする対象が1件の場合はdeleteOneまたはfindOneAndDeleteで複数個の場合は deleteMany bulkWriteのいづれかを利用してください。

また、全て削除したい場合はdrop関数を利用します。

test> db.users.drop()
true
test> db.users.find()

大量のデータ追加

MongoDBのインターフェイスはJavascriptになっています。
そのため、下記のようなコードを実行し大量のデータを追加する事ができます。
※データは挿入に数秒かかる場合があるためご注意ください。

test> for(i=0;i<20000;i++){db.numbers.insertOne({num:i})}
{
  acknowledged: true,
  insertedId: ObjectId("6350b49a39e7cde9bce64131")
}
test> db.numbers.countDocuments()
20000

最終的に2万個のデータが追加できたのがわかると思います。

余談

上記の様に、1個1個保存した場合に時間がかかってしまいます。
ですので、insertManyを使って一括でデータを保存したほうが高速に保存ができるものと思います。

下記のコードは2000個の{num:x}を作成しています。

test> db.numbers2.insertMany(new Array(20000).fill(0).map((v,i)=>{return {num:i}}))

実行したところ、数秒で終わりました。個別に1個ずつ追加するよりやっぱり早いですね…

test> db.numbers2.find({num:19})
[ { _id: ObjectId("6350bab139e7cde9bce64145"), num: 19 } ]
test> db.numbers2.count()
20000

Discussion

ログインするとコメントできます