Open7

MongoDBのCRUD操作について

shinmeishinmei

ローカルでMongoDB環境の用意する。
MongoDBのバージョンは8.0.5を使用。

dockerでMongoDBコンテナを起動

$ docker run -d \
  --name mongodb \
  -e MONGO_INITDB_ROOT_USERNAME=root \
  -e MONGO_INITDB_ROOT_PASSWORD=example \
  -p 27017:27017 \
  mongo:8.0.5

コンテナ起動できてるか確認

$ docker ps
CONTAINER ID   IMAGE         COMMAND                   CREATED          STATUS          PORTS                                           NAMES
a5122ddbe676   mongo:8.0.5   "docker-entrypoint.s…"   19 minutes ago   Up 19 minutes   0.0.0.0:27017->27017/tcp, :::27017->27017/tcp   mongodb

mongoDBコンテナに接続する。
MongoDB shell(mongosh)を使っていく。

$ docker exec -it mongodb mongosh -u root -p example
Current Mongosh Log ID:	67c2bbc5fca64adc14584a20
Connecting to:		mongodb://<credentials>@127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.4.0
Using MongoDB:		8.0.5
Using Mongosh:		2.4.0

For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/

------
   The server generated these startup warnings when booting
   2025-03-01T07:12:50.014+00:00: For customers running the current memory allocator, we suggest changing the contents of the following sysfsFile
   2025-03-01T07:12:50.014+00:00: For customers running the current memory allocator, we suggest changing the contents of the following sysfsFile
   2025-03-01T07:12:50.014+00:00: We suggest setting the contents of sysfsFile to 0.
   2025-03-01T07:12:50.014+00:00: Your system has glibc support for rseq built in, which is not yet supported by tcmalloc-google and has critical performance implications. Please set the environment variable GLIBC_TUNABLES=glibc.pthread.rseq=0
   2025-03-01T07:12:50.014+00:00: vm.max_map_count is too low
   2025-03-01T07:12:50.014+00:00: We suggest setting swappiness to 0 or 1, as swapping can cause performance problems.
------

使用するデータベースでmyDBを選択

> use myDB

ここまでで準備OK

shinmeishinmei

アップデート操作については以下とのこと

MongoDB では、挿入操作は単一のコレクションを対象とします。MongoDB のすべての書き込み (write) 操作は、単一のドキュメントのレベルでアトミックです。

shinmeishinmei

まずは、ドキュメントのInsert
https://www.mongodb.com/ja-jp/docs/manual/tutorial/insert-documents/#insert-documents

MongoDBでは、コレクションを明示的に作成しなくても、ドキュメントをinsertするとコレクションも作成してくれるよう。

insertには以下二つのメソッドがある。一つのドキュメント挿入か、複数のドキュメント挿入か

  • db.collection.insertOne()
  • db.collection.insertMany()

単一ドキュメントのインサート

ドキュメントに_idフィールドを指定せずにinsertすると、_id フィールドも追加される。

// insertOne
myDB> db.inventory.insertOne({
...   item: 'canvas',
...   qty: 100,
...   tags: ['cotton'],
...   size: { h: 28, w: 35.5, uom: 'cm' }
... });

{
  acknowledged: true,
  insertedId: ObjectId('67c2d32efca64adc14584a21')
}

// 確認
myDB> db.inventory.find({ item: 'canvas' });

[
  {
    _id: ObjectId('67c2d32efca64adc14584a21'),
    item: 'canvas',
    qty: 100,
    tags: [ 'cotton' ],
    size: { h: 28, w: 35.5, uom: 'cm' }
  }
]

複数のドキュメントの挿入

// insertMany
myDB> db.inventory.insertMany([
  {
    item: 'journal',
    qty: 25,
    tags: ['blank', 'red'],
    size: { h: 14, w: 21, uom: 'cm' }
  },
  {
    item: 'mat',
    qty: 85,
    tags: ['gray'],
    size: { h: 27.9, w: 35.5, uom: 'cm' }
  },
  {
    item: 'mousepad',
    qty: 25,
    tags: ['gel', 'blue'],
    size: { h: 19, w: 22.85, uom: 'cm' }
  }
]);

{
  acknowledged: true,
  insertedIds: {
    '0': ObjectId('67c2d85efca64adc14584a22'),
    '1': ObjectId('67c2d85efca64adc14584a23'),
    '2': ObjectId('67c2d85efca64adc14584a24')
  }
}

insertedIdsがobjectで返される

shinmeishinmei

次はクエリについて
https://www.mongodb.com/ja-jp/docs/manual/tutorial/query-documents/

// テストデータのinsert
mydb> 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'
  }
]);

コレクション内のすべてのドキュメントを選択

myDB> db.inventory.find({});

等価条件を指定

myDB> db.inventory.find({ status: 'D' });

クエリ演算子を使用して条件を指定

条件指定にクエリ演算子が使える
https://www.mongodb.com/ja-jp/docs/manual/reference/operator/query/#std-label-query-selectors

db.inventory.find({
  status: { $in: ['A', 'D'] }
});

複数のフィールドに条件指定すると、AND条件になる

db.inventory.find({
  status: 'A',
  qty: { $lt: 40 }
});

[
  {
    _id: ObjectId('67c2e0e4fca64adc14584a26'),
    item: 'notebook',
    qty: 50,
    size: { h: 8.5, w: 11, uom: 'in' },
    status: 'A'
  },
  {
    _id: ObjectId('67c2e0e4fca64adc14584a29'),
    item: 'postcard',
    qty: 45,
    size: { h: 10, w: 15.25, uom: 'cm' },
    status: 'A'
  }
]

一方で、OR条件にするためには、$or演算子を使う

db.inventory.find({
  $or: [{status: 'D'}, {qty: {$gt: 30}}]
});

[
  {
    _id: ObjectId('67c2e0e4fca64adc14584a26'),
    item: 'notebook',
    qty: 50,
    size: { h: 8.5, w: 11, uom: 'in' },
    status: 'A'
  },
  {
    _id: ObjectId('67c2e0e4fca64adc14584a27'),
    item: 'paper',
    qty: 100,
    size: { h: 8.5, w: 11, uom: 'in' },
    status: 'D'
  },
  {
    _id: ObjectId('67c2e0e4fca64adc14584a28'),
    item: 'planner',
    qty: 75,
    size: { h: 22.85, w: 30, uom: 'cm' },
    status: 'D'
  },
  {
    _id: ObjectId('67c2e0e4fca64adc14584a29'),
    item: 'postcard',
    qty: 45,
    size: { h: 10, w: 15.25, uom: 'cm' },
    status: 'A'
  }
]
shinmeishinmei

埋め込みドキュメントまたはネストされたドキュメントに対するクエリ
https://www.mongodb.com/ja-jp/docs/manual/tutorial/query-embedded-documents/#query-on-embedded-nested-documents

ドット表記でネストされたフィールドに対するクエリ

'size.uom'とシングルクォートで囲うことで「size.uom」という一つのフィールドとして扱われる

myDB> db.inventory.find({'size.uom': 'in'});
[
  {
    _id: ObjectId('67c2e0e4fca64adc14584a26'),
    item: 'notebook',
    qty: 50,
    size: { h: 8.5, w: 11, uom: 'in' },
    status: 'A'
  },
  {
    _id: ObjectId('67c2e0e4fca64adc14584a27'),
    item: 'paper',
    qty: 100,
    size: { h: 8.5, w: 11, uom: 'in' },
    status: 'D'
  }
]

埋め込み / ネストされたドキュメントとの一致

等価条件をフィールドに指定する場合は、フィールドの順序も含め完全一致する必要がある。
これは要注意だ

myDB> db.inventory.find({size: {h:8.5, w:11, uom:'in'}});
[
  {
    _id: ObjectId('67c2e0e4fca64adc14584a26'),
    item: 'notebook',
    qty: 50,
    size: { h: 8.5, w: 11, uom: 'in' },
    status: 'A'
  },
  {
    _id: ObjectId('67c2e0e4fca64adc14584a27'),
    item: 'paper',
    qty: 100,
    size: { h: 8.5, w: 11, uom: 'in' },
    status: 'D'
  }
]

// w:11とh:8.5の順序が逆なので、データ該当なし
myDB> db.inventory.find({size: { w:11, h:8.5, uom:'in'}});
shinmeishinmei

配列のクエリ
https://www.mongodb.com/ja-jp/docs/manual/tutorial/query-arrays/

配列に等価条件を指定する場合は、<value>は要素の順序を含め、完全一致するドキュメントを返す

myDB> db.inventory.find({tags: ['blank', 'red']})
[
  {
    _id: ObjectId('67c2f187fca64adc14584a2a'),
    item: 'journal',
    qty: 25,
    tags: [ 'blank', 'red' ],
    dim_cm: [ 14, 21 ]
  },
  {
    _id: ObjectId('67c2f187fca64adc14584a2d'),
    item: 'planner',
    qty: 75,
    tags: [ 'blank', 'red' ],
    dim_cm: [ 22.85, 30 ]
  }
]
myDB> db.inventory.find({tags: ['red', 'blank']})
[
  {
    _id: ObjectId('67c2f187fca64adc14584a2b'),
    item: 'notebook',
    qty: 50,
    tags: [ 'red', 'blank' ],
    dim_cm: [ 14, 21 ]
  }
]

配列内の順序や他の要素に関係なく"red" 要素と "blank" 要素の両方を含む配列を検索する場合は、$all 演算子を使う

myDB> db.inventory.find({tags: {$all: ['red', 'blank']}});
[
  {
    _id: ObjectId('67c2f187fca64adc14584a2a'),
    item: 'journal',
    qty: 25,
    tags: [ 'blank', 'red' ],
    dim_cm: [ 14, 21 ]
  },
  {
    _id: ObjectId('67c2f187fca64adc14584a2b'),
    item: 'notebook',
    qty: 50,
    tags: [ 'red', 'blank' ],
    dim_cm: [ 14, 21 ]
  },
  {
    _id: ObjectId('67c2f187fca64adc14584a2c'),
    item: 'paper',
    qty: 100,
    tags: [ 'red', 'blank', 'plain' ],
    dim_cm: [ 14, 21 ]
  },
  {
    _id: ObjectId('67c2f187fca64adc14584a2d'),
    item: 'planner',
    qty: 75,
    tags: [ 'blank', 'red' ],
    dim_cm: [ 22.85, 30 ]
  }
]

tags が要素の 1 つとして文字列 "red" を含む配列があるドキュメントのクエリ

myDB> db.inventory.find({tags: 'red'});
[
  {
    _id: ObjectId('67c2f187fca64adc14584a2a'),
    item: 'journal',
    qty: 25,
    tags: [ 'blank', 'red' ],
    dim_cm: [ 14, 21 ]
  },
  {
    _id: ObjectId('67c2f187fca64adc14584a2b'),
    item: 'notebook',
    qty: 50,
    tags: [ 'red', 'blank' ],
    dim_cm: [ 14, 21 ]
  },
  {
    _id: ObjectId('67c2f187fca64adc14584a2c'),
    item: 'paper',
    qty: 100,
    tags: [ 'red', 'blank', 'plain' ],
    dim_cm: [ 14, 21 ]
  },
  {
    _id: ObjectId('67c2f187fca64adc14584a2d'),
    item: 'planner',
    qty: 75,
    tags: [ 'blank', 'red' ],
    dim_cm: [ 22.85, 30 ]
  }
]