初步探索 MongoDB
使用 mongo image 以及使用 mongo-express GUI tool.
services:
    db:
        image: mongo:8.0.12
        restart: always
        container_name: mongodb
        ports:
            - "27017:27017"
        # command: [--auth]
        environment:
            MONGO_INITDB_ROOT_USERNAME: root
            MONGO_INITDB_ROOT_PASSWORD: password
        volumes:
            - mongo_data:/data/db
    mongo-express:
        image: mongo-express
        restart: always
        ports:
            - 8081:8081
        environment:
            ME_CONFIG_MONGODB_ADMINUSERNAME: root
            ME_CONFIG_MONGODB_ADMINPASSWORD: password
            ME_CONFIG_MONGODB_URL: mongodb://root:password@db:27017/
            ME_CONFIG_BASICAUTH: false
volumes:
  mongo_data:進入容器
docker exec -it mongodb bash連接
mongosh admin -u root -p password顯示 databases
show dbs顯示 collections (類似 RMDBS 中的 table)
show collections顯示 databases version
db.version()建立新的不存在 database
use test官方文件可參考 mongodb-shell
- Insert a Single Document
use test
db.movies.insertOne(
  {
    title: "The Favourite",
    genres: [ "Drama", "History" ],
    runtime: 121,
    rated: "R",
    year: 2018,
    directors: [ "Yorgos Lanthimos" ],
    cast: [ "Olivia Colman", "Emma Stone", "Rachel Weisz" ],
    type: "movie"
  }
)
insertOne()
returns a document that includes the newly inserted document's _id field value.
取回資料
db.movies.find( { title: "The Favourite" } )- Insert Multiple Documents
use test
db.movies.insertMany([
   {
      title: "Jurassic World: Fallen Kingdom",
      genres: [ "Action", "Sci-Fi" ],
      runtime: 130,
      rated: "PG-13",
      year: 2018,
      directors: [ "J. A. Bayona" ],
      cast: [ "Chris Pratt", "Bryce Dallas Howard", "Rafe Spall" ],
      type: "movie"
    },
    {
      title: "Tag",
      genres: [ "Comedy", "Action" ],
      runtime: 105,
      rated: "R",
      year: 2018,
      directors: [ "Jeff Tomsic" ],
      cast: [ "Annabelle Wallis", "Jeremy Renner", "Jon Hamm" ],
      type: "movie"
    }
])insertMany()
returns a document that includes the newly inserted documents' _id field values.
取回全部的資料
db.movies.find( {} )說明語法
use test
db.movies.find()類似 RMDBS 中的
SELECT * FROM moviesSpecify Equality Condition
use test
db.movies.find( { title: "The Favourite" } )類似 RMDBS 中的
SELECT * FROM movies WHERE title = "The Favourite"Specify Conditions Using Query Operators
use test
db.movies.find( { genres: { $in: [ "Drama", "PG-13" ] } } )類似 RMDBS 中的
SELECT * FROM movies WHERE genres in ("Drama", "PG-13")Specify Logical Operators(AND)
use test
db.movies.find( { rated: "R", runtime: { $gte: 120 } } )rated 必須是 R, 然後 runtime 必須大於等於 120
Specify Logical Operators(OR)
use test
db.movies.find( {
     year: 2018,
     $or: [ { runtime: { $gte: 100 } }, { title: "Tag" } ]
} )year 必須是 2018, 然後 runtime 必須大於等於 100 或 title 等於 Tag.
- Update a Single Document
use test
db.movies.updateOne(
  { title: "Jurassic World: Fallen Kingdom" }, {
    $set: {runtime: 77}
  })
db.movies.find( { title: "Jurassic World: Fallen Kingdom" } )
db.movies.updateOne(
  { title: "Jurassic World: Fallen Kingdom" },{
    $set: {runtime: "77"},
    $currentDate: { lastUpdated: true }
})如果沒有的欄位, 會自動建立.
有關 $currentDate 的說明可參考
currentDate
- Update Multiple Documents
use test
db.movies.updateMany(
  { runtime: { $lt: 100 } },
  {
    $set: { runtime: 5, nights: 1 }
  }
)
db.movies.find( { nights: 1 } )- Replace a Document
db.movies.replaceOne(
  { _id: ObjectId("64741819dcd1cd7e37d54731") },
  { test123: 893421, limit: 5000, products: [ "Investment", "Brokerage" ] }
)
db.movies.findOne( { _id: ObjectId("64741819dcd1cd7e37d54731") } )- Delete All Documents
use test
db.movies.deleteMany({})- Delete All Documents that Match a Condition
use test
db.movies.deleteMany( { title: "Tag" } )- Delete Only One Document that Matches a Condition
use test
db.movies.deleteOne( { _id: ObjectId("64741819dcd1cd7e37d54731") } )
db.movies.findOne( { _id: ObjectId("64741819dcd1cd7e37d54731") } )請直接到這邊下載 MongoDB Compass (GUI)
設定 Authentication Method
如果順利登入的話, 會看到類似的介面
另一種選擇 mongo-express GUI tool.
直接進入 http://0.0.0.0:8081/
可以自己選擇喜歡那款 GUI TOOL
透過 PyMongo documentation 把玩 MongoDB
安裝 pymongo
pip3 install pymongo==4.14.0同步範例 code demo.py
from pymongo import MongoClient
from pymongo.errors import ConnectionFailure, ServerSelectionTimeoutError
# 建立連接並處理錯誤
try:
    client = MongoClient('mongodb://root:password@localhost:27017/',
                        serverSelectionTimeoutMS=5000)
    # 測試連接
    client.admin.command('ping')
    print("成功連接到 MongoDB")
except (ConnectionFailure, ServerSelectionTimeoutError) as e:
    print(f"無法連接到 MongoDB: {e}")
    exit(1)
db = client['test']
movies = db['movies']
def insert_demo():
    # insert
    new_profile = {'user_id': 213, 'name': 'Alan'}
    result = movies.insert_one(new_profile)
    print(f"插入文檔 ID: {result.inserted_id}")
    # read
    print("\n所有文檔:")
    for movie in movies.find():
        print(movie)
def update_demo():
    result = movies.update_one({'user_id': 213}, {'$set': {'user_id': 30}})
    print(f"更新了 {result.modified_count} 個文檔")
    # read
    print("\n更新後的文檔:")
    for movie in movies.find():
        print(movie)
def cleanup():
    # 清理測試資料
    result = movies.delete_many({'user_id': {'$in': [213, 30]}})
    print(f"\n清理了 {result.deleted_count} 個文檔")
if __name__ == "__main__":
    try:
        insert_demo()
        # update_demo()
        # cleanup()  # 取消註解以清理測試資料
    finally:
        client.close()
        print("\n已關閉連接")非同步範例 code demo_async.py
import asyncio
from pymongo import AsyncMongoClient
from pymongo.errors import ConnectionFailure, ServerSelectionTimeoutError
# 全域變數
client = None
db = None
movies = None
async def connect():
    """建立非同步連接並處理錯誤"""
    global client, db, movies
    try:
        client = AsyncMongoClient('mongodb://root:password@localhost:27017/',
                                serverSelectionTimeoutMS=5000)
        # 測試連接
        await client.admin.command('ping')
        print("成功連接到 MongoDB")
        db = client['test']
        movies = db['movies']
        return True
    except (ConnectionFailure, ServerSelectionTimeoutError) as e:
        print(f"無法連接到 MongoDB: {e}")
        return False
async def insert_demo():
    """非同步插入示範"""
    # insert
    new_profile = {'user_id': 213, 'name': 'Alan'}
    result = await movies.insert_one(new_profile)
    print(f"插入文檔 ID: {result.inserted_id}")
    # read
    print("\n所有文檔:")
    async for movie in movies.find():
        print(movie)
async def update_demo():
    """非同步更新示範"""
    result = await movies.update_one({'user_id': 213}, {'$set': {'user_id': 30}})
    print(f"更新了 {result.modified_count} 個文檔")
    # read
    print("\n更新後的文檔:")
    async for movie in movies.find():
        print(movie)
async def cleanup():
    """清理測試資料"""
    result = await movies.delete_many({'user_id': {'$in': [213, 30]}})
    print(f"\n清理了 {result.deleted_count} 個文檔")
async def main():
    """主程式"""
    # 建立連接
    if not await connect():
        return
    try:
        await insert_demo()
        # await update_demo()
        # await cleanup()  # 取消註解以清理測試資料
    finally:
        if client:
            await client.close()
            print("\n已關閉連接")
if __name__ == "__main__":
    # 執行非同步主程式
    asyncio.run(main())

