0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MongoDBことはじめ

0
Last updated at Posted at 2025-03-22

MongoDB

MongoDB:開発者向けデータプラットフォーム | MongoDB: ドキュメント指向型のNoSQLデータベース管理システム。

MongoDBを使って、データベースを更新するために何が必要かをいくつか確認してみる。

MongoDBのdockerコンテナの起動

Ubuntu22.04だと純正aptだと入らないようだったので、せっかくならと言うことでMongoDBのdockerコンテナで実行してみることにする。
dockerのインストールはDocker備忘録 #初心者 - Qiitaで済んでいる状態。

docker run -d \
  --name mongodb \
  -p 27017:27017 \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD=secret \
  mongo

で最新版のMongoDBがdockerで走る。
確認のためにsudo docker ps

CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS              PORTS                                             NAMES
d25ac999e428   mongo     "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:27017->27017/tcp, [::]:27017->27017/tcp   mongodb

が表示され、走っていることが確認できる。

docker exec -it mongodb mongosh -u admin -p secretでコンテナに入ると

Current Mongosh Log ID:	67debf3155d7b2192b6b140a
Connecting to:		mongodb://<credentials>@127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.4.2
Using MongoDB:		8.0.5
Using Mongosh:		2.4.2

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


To help improve our products, anonymous usage data is collected and sent to MongoDB periodically (https://www.mongodb.com/legal/privacy-policy).
You can opt-out by running the disableTelemetry() command.

------
   The server generated these startup warnings when booting
   2025-03-22T09:40:29.462+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
   2025-03-22T09:40:30.121+00:00: For customers running the current memory allocator, we suggest changing the contents of the following sysfsFile
   2025-03-22T09:40:30.121+00:00: For customers running the current memory allocator, we suggest changing the contents of the following sysfsFile
   2025-03-22T09:40:30.121+00:00: We suggest setting the contents of sysfsFile to 0.
   2025-03-22T09:40:30.121+00:00: vm.max_map_count is too low
   2025-03-22T09:40:30.121+00:00: We suggest setting swappiness to 0 or 1, as swapping can cause performance problems.
------

test> 

あるいはsudo docker exec -it mongodb bashで通常のコンソールで入った後mongosh -u admin -p secretで同様にコンテナ内でmongoshが起動する。

一般ユーザーの追加

adminmongoshに入り、use mydbで、以下のようにdbにユーザーとパスワードを追加:

mydb> use mydb  // ← 対象のデータベースに切り替え この時点でmydbは存在していなくても構わない
switched to db mydb
mydb> db.createUser({ // この時点でmydbにデータがなくても構わない
  user: "newuser",
  pwd: "yourpassword", //要変更
  roles: [{ role: "readWrite", db: "mydb" }]
})
{ ok: 1 }
mydb> 

mongoshからログアウト後に

mongosh -u newuser -p yourpassword --authenticationDatabase mydb

で、mydbが操作できるシェルに入れる。

test> use mydb
switched to db mydb
mydb> show collections
                               //データが何もないのでブランク
mydb> show dbs
                               //データが何もないのでブランク
mydb> db.sample.insertOne({ name: "Alice", age: 30 }) //データを追加
{
  acknowledged: true,
  insertedId: ObjectId('67decdd70389095b266b140b')
}
mydb> db.sample.find()
[
  { _id: ObjectId('67decdd70389095b266b140b'), name: 'Alice', age: 30 }
]
mydb> show dbs
mydb  8.00 KiB
mydb> show collections
sample
mydb> db.sample.find().pretty()
[
  { _id: ObjectId('67decdd70389095b266b140b'), name: 'Alice', age: 30 }
]
mydb> db.sample.countDocuments()
1
mydb> db.sample.findOne()
{ _id: ObjectId('67decdd70389095b266b140b'), name: 'Alice', age: 30 }

MongoDBでは、RDBの「TABLE」に相当するものがと「collection」と呼ばれている。

MongoDB CompassをリモートからMongoDBに繋げて操作する

MongoDBの公式GUIをMongoDB Compass Download (GUI) | MongoDBからダウンロードする。

手元のホスト(shinohara-mac(仮名))で、MongoDB Compassを起動。
左側のペインにあるCONECTIONSの右にあるをクリックして、接続先の情報を記入する。

  • Name: わかりやすい名前を適当に
  • Advanced Connection Optionsをクリック
    • General
      • Connection String Scheme: mongodb
      • Host: 192.168.xxx.yyy:27017
    • Authentfication
      • Username: newuser
      • Password: yourpassword(要変更)
      • Authentificationdatabase: mydb
        あたりをデフォルトから変えて入力すればOKのはず。これでSave&ConnectをクリックするとDBにアクセスできる。

FastAPI + MongoDBをpodmanコンテナで起動し連携

podmanコンテナが気になったので、FastAPIと併せて使ってみた。PodmanはPodmanことはじめ #初心者 - Qiitaでインストール済み。
ホストのIPアドレスが192.168.10.109であるとする。ホストの$pwd下にmongo-data, appディレクトリを作る:

$pwd/
├── run_MongoDB.sh
├── rm_MongoDB.sh
├── run_FastAPI.sh
├── rm_FastAPI.sh
├── mongo-data/
└── app/
    └── main.py
run_MongoDB.sh
#!/bin/bash
set -euo pipefail

# 既存のコンテナがあれば削除
podman rm -f my-mongo >/dev/null 2>&1 || true

# MongoDB コンテナ
podman run -d \
  --name my-mongo \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD=secretpass \
  -v $(pwd)/mongo-data:/data/db:Z \
  -p 27017:27017 \
  docker.io/library/mongo:latest
rm_MongoDB.sh
#!/bin/bash
set -euo pipefail

# MongoDB コンテナを停止して削除
if podman ps -a --format '{{.Names}}' | grep -q '^my-mongo$'; then
  podman stop my-mongo >/dev/null 2>&1 || true
  podman rm my-mongo >/dev/null 2>&1 || true
  echo "MongoDB コンテナ (my-mongo) を停止・削除しました。"
else
  echo "MongoDB コンテナ (my-mongo) は存在しません。"
fi
run_FastAPI.sh
#!/bin/bash
set -euo pipefail

# 既存のコンテナがあれば削除
podman rm -f my-fastapi >/dev/null 2>&1 || true

# FastAPI コンテナ
#!/bin/bash
set -euo pipefail

# 既存のコンテナがあれば削除
podman rm -f my-fastapi >/dev/null 2>&1 || true

# FastAPI コンテナ起動
podman run -d \
  --name my-fastapi \
  -e MONGO_USER=admin \
  -e MONGO_PASS=secretpass \
  -e MONGO_HOST=192.168.10.109 \ #IPアドレスかホスト名を直打。localhostとかだと動かない
  -e MONGO_PORT=27017 \
  -p 8000:8000 \
  -v $(pwd)/app:/app:Z \
  -w /app \
  docker.io/library/python:3.11-slim \
  bash -c "pip install fastapi uvicorn pymongo && \
          uvicorn main:app --host 0.0.0.0 --port 8000 --reload"
rm_FastAPI.sh
#!/bin/bash
set -euo pipefail

# FastAPI コンテナを停止・削除
if podman ps -a --format '{{.Names}}' | grep -q '^my-fastapi$'; then
  podman stop my-fastapi >/dev/null 2>&1 || true
  podman rm my-fastapi   >/dev/null 2>&1 || true
  echo "FastAPI コンテナ (my-fastapi) を停止・削除しました。"
else
  echo "FastAPI コンテナ (my-fastapi) は存在しません。"
fi
app/main.py
import os
from fastapi import FastAPI
from pydantic import BaseModel, Field
from typing import Any, Optional, Union
from pymongo import MongoClient
from datetime import datetime

# FastAPI アプリケーション
app = FastAPI()

# 環境変数から MongoDB 接続情報を取得
mongo_user = os.environ.get("MONGO_USER", "admin")
mongo_pass = os.environ.get("MONGO_PASS", "secretpass")
mongo_host = os.environ.get("MONGO_HOST", "localhost")
mongo_port = int(os.environ.get("MONGO_PORT", 27017))

# MongoDB クライアント
client = MongoClient(f"mongodb://{mongo_user}:{mongo_pass}@{mongo_host}:{mongo_port}/")
db = client["testdb"]          # データベース
collection = db["items"]       # コレクション

# Pydantic モデルで入力スキーマを定義
class Item(BaseModel):
    schema_version: str = Field("0.1.0", description="スキーマバージョン (semver形式)")
    key: str = Field("", description="key")
    value: Union[str, int, float, dict, list, None] = Field(None, description="value")
    tag: Any = Field(None, description="追加メタ情報")
    created_at: datetime = Field(default_factory=datetime.utcnow, description="作成日時")

@app.get("/")
def root():
    return {"message": "MongoDB with FastAPI is running!"}

@app.post("/items/")
def create_item(item: Item):
    """MongoDB に新しい item を保存"""
    result = collection.insert_one(item.dict())
    return {"inserted_id": str(result.inserted_id)}

@app.get("/items/")
def list_items():
    """MongoDB から全ての items を取得 (_id も含める)"""
    items = []
    for doc in collection.find({}):
        doc["_id"] = str(doc["_id"])  # ObjectId を文字列に変換
        items.append(doc)
    return {"items": items}


from typing import Optional
from fastapi import HTTPException
from bson import ObjectId

# 更新用の Pydantic モデル(部分更新を許す)
class ItemUpdate(BaseModel):
    key: Optional[str] = None
    value: Optional[str] = None
    tag: Optional[Any] = None

@app.put("/items/{item_id}")
def update_item(item_id: str, item: ItemUpdate):
    """MongoDB のアイテムを更新"""
    try:
        oid = ObjectId(item_id)
    except Exception:
        raise HTTPException(status_code=400, detail="Invalid item_id")

    update_data = {k: v for k, v in item.dict().items() if v is not None}
    if not update_data:
        raise HTTPException(status_code=400, detail="No fields provided for update")

    result = collection.update_one({"_id": oid}, {"$set": update_data})

    if result.matched_count == 0:
        raise HTTPException(status_code=404, detail="Item not found")

    return {"updated_id": item_id}

@app.delete("/items/{item_id}")
def delete_item(item_id: str):
    """MongoDB のアイテムを削除"""
    try:
        oid = ObjectId(item_id)
    except Exception:
        raise HTTPException(status_code=400, detail="Invalid item_id")

    result = collection.delete_one({"_id": oid})

    if result.deleted_count == 0:
        raise HTTPException(status_code=404, detail="Item not found")

    return {"deleted_id": item_id}

bash run_MongoDB.sh, bash run_FastAPI.shで起動。podman psでコンテナの起動が確認できればひとまず成功。
http://192.168.10.109:8000/docsでAPIのスキーマが見えていればFastAPIについては問題なし。MongoDBと正しく連携されていればhttp://192.168.10.109:8000/itemsにアクセスできるはず。起動直後は内容が空。
ここに

curl -X POST "http://192.168.10.109:8000/items/" \
     -H "Content-Type: application/json" \
     -d '{"key": "test_key1", "value": 11}'

でデータ追加が出来る。

docker-composeを使っていない理由

Ubuntu22.04に入るpodmanはバージョンが3.4.4と古く、podman up -ddocker-compose.ymlで同等の事をすると、ネットワーク周りでいろいろトラブルがあった。(ホストを介さず、podmanが用意するネットワークで通信できるみたい。多分dockerにも同じのがある)一応、MongoDBとFastAPIは別サービスとして動かせるはずなので、ホストを介して動くように、二つの独立なコンテナがホストの27017番を介してデータをやり取りするようにした。
こうした背景で、ホスト名にホスト外から見えるアドレスを指定する必要があり、192.168.10.109を指定しなければいけなくなったと考えられる。(localhostを指定すると、curlがコケる。)

コマンドまとめ

mongoDBは基本的に、DB毎に何かしらの操作が可能なuserが付属している という建て付けのよう。なので、userの存在の前にDBが必要となる。

use mydb // mydbに以下のuserを追加する
db.createUser({
  user: "myuser",
  pwd: "mypassword",
  roles: [
    { role: "readWrite", db: "mydb" }, //mydbには "readWrite"権限を
    { role: "read", db: "otherdb" } // otherdbには"read"権限を
  ]
})

roleの選択肢

DBレベルでのrole(もっと広い範囲での権限に影響するroleもあるらしい)

ロール名 説明
read 読み取り専用。ドキュメントの検索のみ可能。
readWrite 読み取り+書き込みが可能(挿入、更新、削除など)。
dbAdmin インデックス作成、コレクションの情報取得などが可能。
userAdmin ユーザーの作成・削除が可能(ただしそのDB内に限る)。
dbOwner 上記すべての権限を持つ(readWrite + dbAdmin + userAdmin)。
enableSharding シャーディングの有効化が可能(そのDBに対して)。
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?