背景與需求分析

背景

在資料統計系統的開發中,面對的挑戰主要是如何高效地對結構化資料進行分類、篩選、統計等操作。MongoDB 作為 NoSQL 資料庫,其強大的聚合管線功能提供了靈活的資料操作方式,可以減少應用程式與資料庫之間的交互負擔,提升系統效能。

需求

本實踐的目標是實現兩個功能:

  1. 計算台北市各分區消費者數量與平均年齡:此功能需要根據 district 分組,並統計每個分組的記錄數量與 age 欄位的平均值。
  2. 計算 107 年全台灣的出生、死亡、結婚與離婚統計數據:此功能需針對 year 為 107 的資料,進行多項數據的加總。

工具與環境準備

MongoDB

MongoDB 是一款基於文件的 NoSQL 資料庫,提供強大的查詢功能和聚合管線支援,特別適合處理結構化與半結構化的資料。

C# 與 MongoDB.Driver

  1. C# 是一種成熟且高效的開發語言,適用於構建穩健的後端服務。
  2. MongoDB.Driver 是 MongoDB 提供的官方 .NET 驅動程式,可以方便地將 MongoDB 的操作融入 C# 應用程式中。

安裝指令:

 
bash
Install-Package MongoDB.Driver -Version 2.26.0

資料結構設計

CustomersDocument

對應台北市消費者的分區與年齡資訊,數據結構如下:

  • district: 表示消費者所在的分區(如信義、大安)。
  • age: 表示消費者的年齡。

PeopleDocument

對應全台灣的年度統計數據,結構如下:

  • year: 年份。
  • births: 出生人數。
  • deaths: 死亡人數。
  • marriages: 結婚對數。
  • divorces: 離婚對數。

聚合管線的使用

基本概念

MongoDB 的聚合管線由多個階段組成,每個階段執行特定的操作,如篩選、分組、排序等。每個階段的輸出作為下一階段的輸入,最終返回處理結果。

實踐過程

功能一:計算台北市各分區消費者數量與平均年齡

  1. 數據準備 匯入消費者數據:

     
    json
    [ { "city": "台北市", "district": "信義", "age": 25 }, { "city": "台北市", "district": "松山", "age": 30 } ]
  2. MongoDB 聚合查詢 使用 $match 篩選出 city 為 "台北市" 的記錄,然後使用 $groupdistrict 分組,計算每組的平均年齡與數量:

     
    javascript
    db.customers.aggregate([ { $match: { city: "台北市" } }, { $group: { _id: "$district", avgAge: { $avg: "$age" }, totalCount: { $sum: 1 } } } ]);
  3. C# 實現邏輯

    • 使用 Aggregate() 方法,傳遞匹配與分組操作。
    • 分組後的結果包括分區名稱、平均年齡和總數量。

功能二:計算 107 年全台灣統計數據

  1. 數據準備 匯入統計數據:

     
    json
    [ { "year": 107, "births": 200000, "deaths": 150000, "marriages": 120000, "divorces": 50000 } ]
  2. MongoDB 聚合查詢 使用 $group 將所有資料聚合為一條記錄,分別計算出生、死亡、結婚、離婚的總數:

     
    javascript
    db.people.aggregate([ { $group: { _id: null, totalBirth: { $sum: "$births" }, totalDeath: { $sum: "$deaths" }, totalMarry: { $sum: "$marriages" }, totalDivorce: { $sum: "$divorces" } } } ]);
  3. C# 實現邏輯

    • 使用 Find() 方法篩選 year == 107 的記錄。
    • 將結果直接讀取並輸出。

完整實現程式碼

完整程式碼如之前提供的主程式部分,詳細解釋如下:

  1. 建立 MongoClient 並連接資料庫

     
    csharp
    var client = new MongoClient("mongodb://localhost:27017"); var database = client.GetDatabase("StatisticsDB");
  2. 選擇集合

     
    csharp
    var customersCollection = database.GetCollection<CustomersDocument>("Customers"); var peopleCollection = database.GetCollection<PeopleDocument>("People");
  3. 控制台交互 根據輸入選擇操作功能,執行不同的統計邏輯。


效能與應用場景分析

  1. 高效性

    • 聚合管線在資料庫層執行,減少資料傳輸和程式處理負擔。
    • 篩選、分組、計算等操作一次完成,避免多次查詢的資源消耗。
  2. 應用場景

    • 適用於電商後端數據分析、人口普查、業務報表生成等需求。
  3. 擴展性

    • 可結合更多聚合運算子(如 $project$sort)進行進一步的資料處理。

結論

本實踐展示了如何使用 MongoDB 聚合管線處理複雜查詢需求,並結合 C# 開發實現資料統計系統。這種方式不僅簡化了應用程式邏輯,還顯著提升了效能與可維護性,是構建高效資料處理系統的重要工具。

 

 

第 9 章 MongoDB 進階操作:聚合

9.1 聚合管線概念

在前面第 6 章中,我們學習了基本的 MongoDB 查詢操作(如 find() 方法),這些查詢能滿足簡單的需求。然而,當面臨更為複雜的查詢場景時,多次的 find() 操作可能變得低效且繁瑣。本章將介紹 MongoDB 強大的查詢功能——聚合管線(Aggregation Pipeline),它能有效處理複雜的查詢需求,並簡化數據處理流程。

聚合管線的基本概念

MongoDB 聚合管線是一種數據處理流水線,每個階段執行特定的數據轉換和分析。其核心概念包括:

  • 資料流:文檔從集合中流入管線。

  • 階段:管線由多個階段組成,每個階段執行特定操作。

  • 轉換:每個階段可對數據進行篩選、轉換或分組。

  • 結果:管線的最後階段輸出處理完成的結果。

聚合管線的優勢

  1. 高效性:所有操作均在資料庫內完成,減少了數據傳輸的成本。

  2. 靈活性:支持多種組合操作,實現複雜的數據轉換。

  3. 可讀性:階段化的結構使得複雜查詢更容易理解與維護。

聚合管線的應用場景包括計算平均值、統計總和、分組數據等,能在一次查詢中完成多種操作。


簡單查詢與複雜查詢的使用情境

假設我們有一個包含台灣各分區人口資料的集合 people,其中每筆文檔的字段包括 _idcity(城市)、district(分區)、sex(性別)。

範例數據:

{
  "_id": "A123456789", "city": "台北市", "district": "信義", "sex": "男"
},
{
  "_id": "A123456790", "city": "台北市", "district": "松山", "sex": "女"
}
簡單查詢:一次查詢即可獲得結果
  1. 計算總人數

    db.people.countDocuments();
  2. 查詢台北市的人口數

    db.people.countDocuments({ city: "台北市" });
  3. 查詢台北市男性的人口數

    db.people.countDocuments({ city: "台北市", sex: "男" });
複雜查詢:需要多次查詢

查詢台北市信義區男性與松山區女性的總人數:

  1. 信義區男性人數

    db.people.countDocuments({ city: "台北市", district: "信義", sex: "男" });
  2. 松山區女性人數

    db.people.countDocuments({ city: "台北市", district: "松山", sex: "女" });

將結果相加得出答案。


9.1.3 聚合管線的操作

優點

  • 相比傳輸所有原始數據,只傳輸統計結果,大幅節省資源。

  • 自動識別分區數量,減少查詢次數。

缺點

  • 無法取得原始數據。

聚合操作的步驟
  1. 定義問題:例如,統計台灣每個城市分區的男性與女性人數。

  2. 聚合過程

    • 篩選:過濾出符合條件的文檔。

    • 分組:根據分區字段進行分組。

    • 計算:統計每組中的男性與女性數量。

    • 輸出:將結果返回給用戶。

聚合查詢示例:

// 聚合查詢示例
db.people.aggregate([
  { $group: { _id: "$district", male: { $sum: { $cond: [ { $eq: ["$sex", "男"] }, 1, 0 ] } }, female: { $sum: { $cond: [ { $eq: ["$sex", "女"] }, 1, 0 ] } } } }
]);

9.2 聚合運算子

MongoDB 提供超過 30 種的聚合運算子,用於支持豐富的數據處理操作。以下是常見運算子:

運算子 說明
$match 篩選符合條件的文檔。
$group 根據指定字段分組並進行統計。
$project 映射輸出字段。
$limit 限制返回的文檔數量。
$sort 對結果進行排序。

範例:計算每個分區的消費者平均年齡

db.customers.aggregate([
  { $match: { city: "台北市" } },
  { $group: { _id: "$district", avgAge: { $avg: "$age" }, totalCount: { $sum: 1 } } }
]);

9.3 使用範例

範例 1:計算台北市消費者數量與平均年齡
  1. 匯入資料

    db.customers.insertMany([
      { "city": "台北市", "district": "信義", "age": 25 },
      { "city": "台北市", "district": "松山", "age": 30 }
    ]);
  2. 聚合查詢

    db.customers.aggregate([
      { $match: { city: "台北市" } },
      { $group: { _id: "$district", avgAge: { $avg: "$age" }, totalCount: { $sum: 1 } } }
    ]);

    結果:每個分區的消費者平均年齡和總人數。

範例 2:全台灣 107 年出生、死亡、結婚、離婚數據統計
  1. 匯入資料:匯入政府開放平台的戶籍資料。

  2. 聚合查詢

    db.people.aggregate([
      { $group: { _id: null, totalBirth: { $sum: "$birth_total" }, totalDeath: { $sum: "$death_total" }, totalMarry: { $sum: "$marry_pair" }, totalDivorce: { $sum: "$divorce_pair" } } }
    ]);

    結果:返回全台灣的統計數據。


9.4 實戰演練:資料統計系統

此範例使用 C# 搭配 MongoDB Driver 實現數據統計系統,並通過控制台操作執行兩個功能:

  1. 計算台北市各分區消費者數量與平均年齡。

  2. 計算 107 年全台灣的出生、死亡、結婚與離婚統計數據。

主要步驟

  1. 安裝 MongoDB Driver

    Install-Package MongoDB.Driver -Version 2.26.0
  2. 定義數據結構

    • CustomersDocument.cs

    • `PeopleDocument.cs

 

9.4 實戰演練:資料統計系統 此範例使用 C# 搭配 MongoDB Driver 實現數據統計系統,並通過控制台操作執行兩個功能: 計算台北市各分區消費者數量與平均年齡。 計算 107 年全台灣的出生、死亡、結婚與離婚統計數據。 主要步驟 安裝 MongoDB Driver: Install-Package MongoDB.Driver -Version 2.26.0 定義數據結構: CustomersDocument.cs PeopleDocument.cs
ChatGPT 說:
ChatGPT

以下是一個簡單的 C# 方案,使用 MongoDB.Driver 來實現資料統計系統的主要功能。


安裝 MongoDB.Driver

 
bash
Install-Package MongoDB.Driver -Version 2.26.0

定義數據結構

CustomersDocument.cs

 
csharp
using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; public class CustomersDocument { [BsonId] public ObjectId Id { get; set; } [BsonElement("district")] public string District { get; set; } [BsonElement("age")] public int Age { get; set; } }

PeopleDocument.cs

 
csharp
using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; public class PeopleDocument { [BsonId] public ObjectId Id { get; set; } [BsonElement("year")] public int Year { get; set; } [BsonElement("births")] public int Births { get; set; } [BsonElement("deaths")] public int Deaths { get; set; } [BsonElement("marriages")] public int Marriages { get; set; } [BsonElement("divorces")] public int Divorces { get; set; } }

主程式

 
csharp
using System; using System.Linq; using MongoDB.Driver; class Program { static void Main(string[] args) { var connectionString = "mongodb://localhost:27017"; var client = new MongoClient(connectionString); var database = client.GetDatabase("StatisticsDB"); var customersCollection = database.GetCollection<CustomersDocument>("Customers"); var peopleCollection = database.GetCollection<PeopleDocument>("People"); Console.WriteLine("選擇操作: "); Console.WriteLine("1. 計算台北市各分區消費者數量與平均年齡"); Console.WriteLine("2. 計算107年全台灣的出生、死亡、結婚與離婚統計數據"); Console.Write("請輸入選項: "); var choice = Console.ReadLine(); switch (choice) { case "1": CalculateCustomerStatistics(customersCollection); break; case "2": CalculateYearlyStatistics(peopleCollection); break; default: Console.WriteLine("無效選項"); break; } } static void CalculateCustomerStatistics(IMongoCollection<CustomersDocument> collection) { var groups = collection.Aggregate() .Group(c => c.District, g => new { District = g.Key, Count = g.Count(), AverageAge = g.Average(c => c.Age) }) .ToList(); Console.WriteLine("台北市各分區統計:"); foreach (var group in groups) { Console.WriteLine($"分區: {group.District}, 消費者數量: {group.Count}, 平均年齡: {group.AverageAge:F2}"); } } static void CalculateYearlyStatistics(IMongoCollection<PeopleDocument> collection) { var yearData = collection.Find(p => p.Year == 107).FirstOrDefault(); if (yearData != null) { Console.WriteLine($"107 年統計數據:"); Console.WriteLine($"出生: {yearData.Births}"); Console.WriteLine($"死亡: {yearData.Deaths}"); Console.WriteLine($"結婚: {yearData.Marriages}"); Console.WriteLine($"離婚: {yearData.Divorces}"); } else { Console.WriteLine("無 107 年的數據"); } } }

MongoDB 資料結構

Customers Collection

 
json
[ { "district": "中正區", "age": 25 }, { "district": "大安區", "age": 30 }, { "district": "中正區", "age": 35 } ]

People Collection

 
json
[ { "year": 107, "births": 200000, "deaths": 150000, "marriages": 120000, "divorces": 50000 } ]

執行結果範例

選擇 1:

 
plaintext
台北市各分區統計: 分區: 中正區, 消費者數量: 2, 平均年齡: 30.00 分區: 大安區, 消費者數量: 1, 平均年齡: 30.00

選擇 2:

 
plaintext
107 年統計數據: 出生: 200000 死亡: 150000 結婚: 120000 離婚: 50000

 

創作者介紹
創作者 AI革命家 REVOLUTIONARY 的頭像
AI革命家

AI革命家 REVOLUTIONARY

AI革命家 發表在 痞客邦 留言(0) 人氣( 0 )