MongoDB 作為一種 NoSQL 資料函式庫,以其靈活的檔案模型和豐富的查詢功能而聞名。本文除了介紹基本的 CRUD 操作外,也涵蓋了進階的查詢技巧,例如 $or$in 等,以及如何使用投影操作來提升查詢效率。此外,文章也探討了 MongoDB 的聚合框架,讓開發者能夠運用其強大的資料處理能力進行資料分析和統計。

MongoDB 資料函式庫操作

更新檔案

在 MongoDB 中,更新檔案是常見的操作。可以使用 updateMany() 方法更新多個檔案,或使用 replaceOne() 方法替換整個檔案。

更新多個欄位

db.people.updateMany({name: 'Tom'}, {$set: {age: 30, salary: 50000}})

這將更新所有名字為 ‘Tom’ 的檔案,將年齡設為 30,並新增一個 salary 欄位,值為 50000。

替換檔案

db.collection.replaceOne({name: 'Tom'}, {name: 'Lakmal', age: 25, address: 'Sri Lanka'})

這將替換名字為 ‘Tom’ 的檔案,新的檔案將包含 nameageaddress 欄位。注意,用於識別檔案的欄位將被保留在更新的檔案中,未在更新區段中定義的欄位將被移除。

刪除檔案

MongoDB 提供了多種方法來刪除檔案。

刪除多個檔案

db.people.deleteMany({name: 'Tom'})

這將刪除所有名字為 ‘Tom’ 的檔案。

刪除單個檔案

db.people.deleteOne({name: 'Tom'})

這將刪除第一個名字為 ‘Tom’ 的檔案。

查詢檔案

查詢是 MongoDB 中最常用的操作之一。

查詢所有符合條件的檔案

db.people.find({name: 'Tom'})

這將傳回所有名字為 ‘Tom’ 的檔案。

查詢第一個符合條件的檔案

db.people.findOne({name: 'Tom'})

這將傳回第一個名字為 ‘Tom’ 的檔案。

指定傳回欄位

db.people.find({name: 'Tom'}, {_id: 0, age: 1})

這將傳回名字為 ‘Tom’ 的檔案的 age 欄位,並排除 _id 欄位。

更新內嵌檔案

內嵌檔案是指巢狀在其他檔案中的檔案。

使用 $ 運算元更新內嵌檔案

db.people.update({name: "Tom", marks: 50}, {"$set": {"marks.$": 55}})

這將更新名字為 ‘Tom’ 且 marks 陣列中包含 50 的檔案,將 50 更新為 55。

更多更新運算元

MongoDB 提供了多種更新運算元,例如 $push$pull$pop

$push 運算元

db.people.update({name: 'Tom'}, {$push: {nicknames: 'Tommy'}})

這將在名字為 ‘Tom’ 的檔案的 nicknames 陣列中新增一個元素 ‘Tommy’。

$pull 運算元

db.people.update({name: 'Tom'}, {$pull: {nicknames: 'Tommy'}})

這將從名字為 ‘Tom’ 的檔案的 nicknames 陣列中移除元素 ‘Tommy’。

更新多個檔案的引數

要更新多個檔案,需要設定 multi 選項為 true

db.collection.update(
    query,
    update,
    {
        upsert: boolean,
        multi: boolean,
        writeConcern: document
    }
)

取得資料函式庫資訊

MongoDB 提供了多種方法來取得資料函式庫資訊。

列出所有集合

show collections

db.getCollectionNames()

列出所有資料函式庫

show dbs

db.adminCommand('listDatabases')

MongoDB 查詢資料基礎

MongoDB 提供多種查詢方法來檢索資料,包括 find()findOne() 等,並支援多種條件查詢,如 AND、OR、IN 等。

4.1 使用 find() 查詢資料

find() 方法用於檢索集合中的檔案。

檢索集合中的所有檔案

db.collection.find({});

使用條件檢索檔案(類別似於 MySQL 中的 WHERE)

db.collection.find({key: value});

範例:

db.users.find({email:"sample@email.com"});

使用布林條件查詢(Query Operators)

AND
db.collection.find({
  $and: [
    { key: value }, 
    { key: value }
  ]
})
OR
db.collection.find({
  $or: [
    { key: value }, 
    { key: value }
  ]
})
NOT
db.inventory.find({ key: { $not: value } })

更多布林操作和範例可參考相關檔案。

注意事項

find() 會持續搜尋集合,即使已經找到符合的檔案。因此,在大型集合中使用時效率較低。然而,透過仔細設計資料模型和使用索引,可以提高 find() 的效率。

4.2 使用 findOne() 查詢資料

findOne() 的查詢功能與 find() 類別似,但它會在找到第一個符合條件的檔案後停止執行。如果使用空物件作為查詢條件,它會取出第一個檔案並傳回。

db.collection.findOne({});

4.3 對 find() 結果進行限制、跳過、排序和計數

與聚合方法類別似,find() 也支援對結果進行限制、跳過、排序和計數。

範例集合

db.test.insertMany([
  {name:"Any", age:"21", status:"busy"},
  {name:"Tony", age:"25", status:"busy"},
  {name:"Bobby", age:"28", status:"online"},
  {name:"Sonny", age:"28", status:"away"},
  {name:"Cher", age:"20", status:"online"}
])

列出集合中的所有檔案

db.test.find({})

結果:

{ "_id" : ObjectId("592516d7fbd5b591f53237b0"), "name" : "Any", "age" : "21", "status" : "busy" }
{ "_id" : ObjectId("592516d7fbd5b591f53237b1"), "name" : "Tony", "age" : "25", "status" : "busy" }
{ "_id" : ObjectId("592516d7fbd5b591f53237b2"), "name" : "Bobby", "age" : "28", "status" : "online" }
{ "_id" : ObjectId("592516d7fbd5b591f53237b3"), "name" : "Sonny", "age" : "28", "status" : "away" }
{ "_id" : ObjectId("592516d7fbd5b591f53237b4"), "name" : "Cher", "age" : "20", "status" : "online" }

跳過前3個檔案

db.test.find({}).skip(3)

結果:

{ "_id" : ObjectId("592516d7fbd5b591f53237b3"), "name" : "Sonny", "age" : "28", "status" : "away" }
{ "_id" : ObjectId("592516d7fbd5b591f53237b4"), "name" : "Cher", "age" : "20", "status" : "online" }

按名稱欄位降序排序

db.test.find({}).sort({ "name" : -1})

結果:

{ "_id" : ObjectId("592516d7fbd5b591f53237b1"), "name" : "Tony", "age" : "25", "status" : "busy" }
{ "_id" : ObjectId("592516d7fbd5b591f53237b3"), "name" : "Sonny", "age" : "28", "status" : "away" }
{ "_id" : ObjectId("592516d7fbd5b591f53237b4"), "name" : "Cher", "age" : "20", "status" : "online" }
{ "_id" : ObjectId("592516d7fbd5b591f53237b2"), "name" : "Bobby", "age" : "28", "status" : "online" }
{ "_id" : ObjectId("592516d7fbd5b591f53237b0"), "name" : "Any", "age" : "21", "status" : "busy" }

計數結果數量

db.test.find({}).count()

結果:

5

組合使用這些方法

例如,取得排序後集合中跳過第1個檔案並限制傳回2個檔案的結果:

db.test.find({}).sort({ "name" : -1}).skip(1).limit(2)

結果:

{ "_id" : ObjectId("592516d7fbd5b591f53237b3"), "name" : "Sonny", "age" : "28", "status" : "away" }
{ "_id" : ObjectId("592516d7fbd5b591f53237b4"), "name" : "Cher", "age" : "20", "status" : "online" }

4.4 使用 AND、OR 和 IN 條件查詢檔案

students 集合中的所有檔案

db.students.find().pretty();

結果:

{
  "_id" : ObjectId("58f29a694117d1b7af126dca"),
  "studentNo" : 1,
  "firstName" : "**Prosen**",
  ...
}
...

對應的 MySQL 查詢陳述式

SELECT * FROM students;

使用條件查詢

例如,查詢 firstName 為 “Prosen” 的學生:

db.students.find({firstName:"**Prosen**"});

對應的 MySQL 查詢陳述式:

SELECT * FROM students WHERE firstName = "**Prosen**";

AND 查詢

查詢 firstName 為 “Prosen",且 age 大於等於23的學生:

db.students.find({
  "**firstName**": "**Prosen**",
  "**age**": {
    "$gte": 23
  }
});

對應的 MySQL 查詢陳述式:

SELECT * FROM students WHERE firstName = "**Prosen**" AND age >= 23;

OR 查詢

查詢 firstName 為 “Prosen",或 age 大於等於23的學生:

db.students.find({
  "$or": [{
    "**firstName**": "**Prosen**"
  }, {
    "**age**": {
      "$gte": 23
    }
  }]
});

對應的 MySQL 查詢陳述式:

SELECT * FROM students WHERE firstName = "**Prosen**" OR age >= 23;

MongoDB 查詢與更新操作深入解析

MongoDB 是一種 NoSQL 資料函式庫,其查詢與更新操作具有靈活性和高效性。本文將探討 MongoDB 的查詢與更新操作,包括 $or 查詢、$in 查詢、投影(Projection)、更新運算元(Update Operators)等。

$or 查詢與 $in 查詢

在 MongoDB 中,$or 查詢用於滿足多個條件中的至少一個。例如:

db.students.find({
  firstName: "Prosen",
  $or: [
    { age: 23 },
    { age: 25 }
  ]
});

上述查詢將傳回 firstName 為 “Prosen” 且 age 為 23 或 25 的檔案。對應的 MySQL 查詢陳述式為:

SELECT * FROM students WHERE firstName = "Prosen" AND (age = 23 OR age = 25);

$in 查詢則用於匹配某個欄位的值是否在給定的陣列中。例如:

db.students.find({ lastName: { $in: ["Ghosh", "Amin"] } });

上述查詢將傳回 lastName 為 “Ghosh” 或 “Amin” 的檔案。對應的 MySQL 查詢陳述式為:

SELECT * FROM students WHERE lastName IN ('Ghosh', 'Amin');

內容解密:

  • $or 用於多條件查詢,只要滿足其中一個條件即可傳回結果。
  • $in 用於檢查某個欄位的值是否在給定的陣列中,提高了查詢的效率和可讀性。

投影(Projection)

投影是指在查詢結果中只傳回指定的欄位,而不是整個檔案。MongoDB 的 find() 方法支援投影操作。例如:

db.people.find({}, { age: 0 });

上述查詢將傳回所有檔案,但不包含 age 欄位。對應地,如果只想傳回 age 欄位,可以使用:

db.people.find({}, { age: 1 });

需要注意的是,預設情況下,_id 欄位總是會被傳回。如果不想傳回 _id,需要顯式指定:

db.people.find({}, { name: 1, _id: 0 });

內容解密:

  • 投影操作允許開發者控制查詢結果中傳回的欄位,提高了資料處理的效率。
  • 使用 1 表示包含該欄位,使用 0 表示排除該欄位。

更新運算元(Update Operators)

MongoDB 提供了多種更新運算元,用於更新檔案中的特定欄位。其中,$set 是最常用的更新運算元之一。

例如,假設有一個 student 集合,需要將名字為 “Tom” 的學生的性別從 “M” 改為 “F”。如果直接使用以下更新陳述式:

db.student.update({ name: 'Tom' }, { sex: 'F' });

將導致整個檔案被替換,只剩下 sex 欄位。正確的做法是使用 $set

db.student.update({ name: 'Tom' }, { $set: { sex: 'F' } });

這樣,只有 sex 欄位被更新,其他欄位保持不變。

內容解密:

  • $set 更新運算元允許開發者更新檔案中的特定欄位,而不影響其他欄位。
  • 正確使用更新運算元可以避免意外覆寫其他重要資料。

MongoDB 聚合框架詳解

MongoDB 的聚合框架(Aggregation Framework)是一種強大的資料處理工具,能夠對資料進行複雜的處理和分析。本文將深入介紹 MongoDB 聚合框架的基本概念、使用方法和實際應用範例。

聚合框架基礎

聚合框架是一種根據管道(Pipeline)的資料處理模型。資料透過一系列的階段(Stage)進行處理,每個階段對資料進行特定的操作,如篩選、分組、排序等。

管道階段

聚合管道由多個階段組成,每個階段都有特定的功能。常見的階段包括:

  • $match:篩選資料,類別似於 SQL 中的 WHERE 子句。
  • $group:分組資料,類別似於 SQL 中的 GROUP BY 子句。
  • $project:投影資料,選擇需要的欄位。
  • $sort:排序資料。
  • $limit:限制輸出結果的數量。
  • $unwind:展開陣列欄位。

實際應用範例

統計交易資料

假設我們有一個交易資料集合 transactions,包含欄位 cr_dr(交易型別)和 amount(交易金額)。我們可以使用聚合框架來統計不同交易型別的數量和總金額。

db.transactions.aggregate([
  {
    $group: {
      _id: '$cr_dr',
      count: {$sum: 1},
      totalAmount: {$sum: '$amount'}
    }
  }
]);

輸出結果:

{
  "_id": "C",
  "count": 3,
  "totalAmount": 120
}
{
  "_id": "D",
  "count": 5,
  "totalAmount": 410
}

計算平均值

我們可以使用 $avg 聚合運算元來計算不同交易型別的平均金額。

db.transactions.aggregate([
  {
    $group: {
      _id: '$cr_dr',
      averageAmount: {$avg: '$amount'}
    }
  }
]);

輸出結果:

{
  "_id": "C",
  "averageAmount": 40
}
{
  "_id": "D",
  "averageAmount": 82
}

處理陣列資料

當我們需要處理陣列欄位時,可以使用 $unwind 階段來展開陣列。

db.inventory.aggregate([
  {
    $unwind: "$sizes"
  }
]);

輸出結果:

{
  "_id": 1,
  "item": "myItem1",
  "sizes": "S"
}
{
  "_id": 1,
  "item": "myItem1",
  "sizes": "M"
}
{
  "_id": 1,
  "item": "myItem1",
  "sizes": "L"
}