# mongo DB(二) MongoDB 存取的是BSON(二進制 JSON)格式來表示。 ## 題目 找出朋友中有amy 且有john 的資料 請把所有人的hobbies都加入reading 和 watch movie 找出email是帶有yahoo的資料 請找出25歲以下 或興趣有painting的資料 請把amy的email改成Amy@google.com,並且新增一個欄位是update_time 內容為現在時間 請把bob john加入sex:M的資料和欄位update_time 為現在時間 Alice Amy 加入sex:F的資料和欄位update_time為現在時間 db.student.update({name:{$in:["Bob,"john]}},{$set:{sex:"M",update_time: new Date()}},{ multi: true } //另一種方法 請將alice的歲數乘2 請讓所有資料的age欄位至少要20歲 請將性別為男生的資料篩選出來並排序且不顯示欄位_id show dbs use mongo_class db.student.insert([ { name: "John", age: 25, email: "john@yahoo.com", hobbies: ["reading", "hiking"], friends: ["Alice", "Bob", "Amy"] }, { name: "Alice", age: 30, email: "alice@example.com", hobbies: ["painting", "gardening"], friends: ["John", "Bob"] }, { name: "Bob", age: 28, email: "bob@example.com", hobbies: ["cooking", "photography"], friends: ["John", "Alice", "Amy"] }, { name: "Amy", age: 18, email: "AA@google.com", hobbies: ["cooking", "photography", "hiking"], friends: ["John", "Alice"] } ] ) db.getCollection('student').find({ friends: { $all: ['Amy', 'John'] } }); // 查詢同時具有 'Amy' 和 'John' 作為朋友的學生資料 db.student.update({}, { $push: { "hobbies": { $each: ["reading", "watch movie"] } } }, { multi: true }); // 將 "reading" 和 "watch movie" 插入所有學生的 hobbies 陣列中 db.getCollection('student').find({ email: { $regex: "yahoo" } }); // 查詢 email 中包含 "yahoo" 的學生資料 db.getCollection('student').find({ $or: [{ age: { $lt: 25 } }, { hobbies: "painting" }] }); // 查詢年齡小於 25 或擁有 "painting" 興趣的學生資料 db.student.update({ name: "Amy" }, { $set: { email: "Amy@google.com", update_time: new Date() } }, { upsert: false }); // 更新名為 "Amy" 的學生的 email 和 update_time 欄位 db.student.update({ $or: [{ name: "Bob" }, { name: "John" }] }, { $set: { sex: "M", update_time: new Date() } }, { multi: true }); // 將名為 "Bob" 或 "John" 的學生的性別設置為 "M",並更新 update_time db.student.update({ $or: [{ name: "Alice" }, { name: "Amy" }] }, { $set: { sex: "F", update_time: new Date() } }, { multi: true }); // 將名為 "Alice" 或 "Amy" 的學生的性別設置為 "F",並更新 update_time db.student.update({ name: "Alice" }, { $mul: { age: 2 } },{ multi: true }); // 將名為 "Alice" 的學生的年齡乘以 2 db.student.update({}, { $max: { age: 20 } }, { multi: true }); // 將年齡小於 20 歲的學生的年齡設置為 20 db.student.update({ age: { $lt: 20 } }, { $set: { age: 20 } }, { multi: true });// 將年齡小於 20 歲的學生的年齡設置為 20 另一種方法 db.getCollection('student').find({ sex: "M" }, { _id: 0 }).sort({ age: 1 }); // 查詢性別為 "M" 的學生資料,並按照年齡升序排列,不顯示 _id 欄位 查詢總比數 db.people.count() db.people.count({city:台北}) db.people.count({city:台北,sex:男}) ## Aggregate db.collection.aggregate() show dbs // 顯示所有的數據庫 use mongo_class // 切換到 mongo_class 數據庫 db.agg.insert({"id" : 1 ,"name" : "mark","age" : 20, "assets" :100000000 }) // 向 agg 集合插入一個文檔 db.agg.insert({"id" : 2, "name" : "steven", "age" : 40, "assets" :1000000 }) // 向 agg 集合插入一個文檔 // 使用聚合操作進行文檔轉換和選擇特定字段 db.agg.aggregate([{"$project":{"id":1,"name":1}}]) // 將 id 和 name 字段保留,其他字段過濾掉 // 使用聚合操作進行文檔篩選和過濾 db.agg.aggregate([{"$match":{age:{$gt:10,$lte:30}}}]) // 選擇 age 字段大於 10 且小於等於 30 的文檔 ## aggregate $sum $max運算值 ![](https://hackmd.io/_uploads/B1I5VQ3D2.png) ![](https://hackmd.io/_uploads/B1gjN7hv3.png) db.students.update({ name: "Alice" },{ $max: { age: 25 } }) 上述示例將更新 students 集合中 name 為 "Alice" 的文檔的 age 字段值,如果 age 字段的當前值小於 25,則更新為 25。 db.students.aggregate([ { $group:{_id: null,maxAge: { $max: "$age" }}}, {$project: {_id: 0,maxAge: 1} } ]).forEach(function(result) {db.students.update( { name: "Alice" }, { $max: { age: result.maxAge } });}); 首先使用 $group 階段計算了集合中所有文檔的 age 字段的最大值,並將結果保存在 maxAge 字段中。然後使用 $project 階段排除了 _id 字段,只保留了 maxAge 字段。最後,使用 forEach 循環遍歷結果,將 maxAge 的最大值應用到 name 為 "Alice" 的文檔的 age 字段上,使用 $max 總之$group 是聚合管道中的操作符,用於按指定字段將文檔分組。通過 $group,您可以對分組後的文檔應用各種聚合操作,例如計算總和、平均值、計數等。 $max 是 $group 階段中使用的一個聚合運算符,用於在分組後的文檔中找到指定字段的最大值。 $max 運算符需要指定要找到最大值的字段 ### 練習一 show dbs use mongo_class db.ox.insert({"id" :1 , "status" : "o" , "count" : 5}) db.ox.insert({"id" :2 , "status" : "o", "count" : 5}) db.ox.insert({"id" :3 , "status" : "o", "count" : 5}) db.ox.insert({"id" :4 , "status" : "x", "count" : 10}) db.ox.insert({"id" :5 , "status" : "x", "count" : 10}) db.ox.insert({"id" :6 , "status" : "x", "count" : 11}) db.ox.aggregate([{"$group":{"_id":"$status"}}]) db.ox.aggregate([{"$group":{"_id":"$status","total":{"$sum":"$count"}}}]) db.ox.aggregate([{"$group":{"_id":{"a":"$status","b":"$count"}}}]) 1.$group 操作按照 status 欄位的值進行分組,將具有相同 status 值的文檔分為一組。_id 指定了分組的依據,這裡使用 status 作為分組依據。 2.使用 $group 階段,通過 _id 欄位將文檔分組為不同的狀態。然後使用 $sum 運算符計算每個狀態的 count 欄位的總和 3.使用 $group 階段,並使用 _id 欄位來創建一個組合鍵,其中包含 status 欄位的值作為 a,count 欄位的值作為 b。 ### 練習二 show dbs use mongo_class db.agg2.insert({"name" : "mark", "fans" : [ {"name" : "steven","age":20}, {"name" : "max","age":60}, {"name" : "stanly","age":30} ]}) db.agg2.aggregate([{"$unwind":"$fans"}]) 使用 $unwind 階段展開 fans 陣列,將每個 fans 對象拆分為單獨的文檔。 ### 練習三 show dbs use mongo_class db.agg3.insert({"name" : "mark", "age" : 18}) db.agg3.insert({"name" : "steven", "age" : 38}) db.agg3.insert({"name" : "max", "age" : 10}) db.agg3.insert({"name" : "stanlly", "age" : 28}) db.agg3.aggregate([{"$sort":{"age":1}}]) db.agg3.aggregate([{"$limit":2}]) db.agg3.aggregate([{"$skip":3}]) 1. db.agg3.aggregate([{"$sort":{"age":1}}]): 這個聚合操作使用 $sort 階段按照 age 字段進行升序排序。結果將按照年齡從小到大排序。 2. db.agg3.aggregate([{"$limit":2}]): 這個聚合操作使用 $limit 階段限制結果集的數量為 2。它將只返回前兩個文檔作為結果。 3. db.agg3.aggregate([{"$skip":3}]): 這個聚合操作使用 $skip 階段跳過前 3 個文檔。它將從第 4 個文檔開始返回結果。 ### 練習四 show dbs use mongo_class db.agg4.insert({ "id" : 1,"name" : "mark","age" : 20,"sex" : "M", "fans": [{"name" : "steven"},{"name" : "max"}],"phone" : "xxxxx"}) db.agg4.insert({ "id" : 2,"name" : "steven", "age" : 40,"sex" :"M","fans" : [{"name" : "mark"},{"name" : "max"}],"phone" : "xxxxx"}) db.agg4.insert({ "id" : 3,"name" : "marry","age" : 30,"sex" : "S", "fans": [{"name" : "mark"},{"name" : "max"},{"name" : "jack"}], "phone" :"xxxxx"}) db.agg4.insert({ "id" : 4,"name" : "jack","age" : 21,"sex" : "M","fans" :[{"name" : "mark"}],"phone" : "xxxxx" }) db.agg4.aggregate([ { $sort: { age: 1 } }, // 按年齡升序排序 { $match: { age: { $gt: 19, $lte: 29 } } }, // 年齡在 20 到 29 歲之間的文檔 { $skip: 1 } // 跳過第一個文檔 ]) db.agg4.aggregate([{"$match":{"sex":"M"}},{"$project":{"name":1,"age":1}},{ $sort: { age: 1 } }, // 按年齡升序排序 { $skip: 1 }, // 跳過第一個文檔 { $limit: 1 } // 返回一個文檔 ]) ## mapReduce練習一 show dbs use mongo_class db.order.insertMany([{ "class" : "1", "price" : 10,"count" : 180}, { "class" : "1" ,"price" : 10,"count" : 350}, { "class" : "2" ,"price" : 10,"count" : 90}, { "class" : "2" ,"price" : 10,"count" : 320}, { "class" : "2" ,"price" : 10,"count" : 150}]) var result = db.order.mapReduce( // 映射函式 function() { // 計算價格和數量的乘積 var total = this.price * this.count; // 使用 "class" 作為鍵(key),將結果發射(emit)出來 emit(this.class, total); }, // 減少函式 function(key, values) { var total = 0; // 將同一鍵的所有值進行加總 for (var i = 0; i < values.length; i++) { total += values[i]; } // 返回每個 "class" 的總和 return total; }, // 選項:指定結果存儲的集合名稱為 "mapReduceTest" { out: "mapReduceTest" } ); // 檢索 "mapReduceTest" 集合中的所有文檔 db.mapReduceTest.find(); ## mapReduce練習二 show dbs use mongo_class db.order_2.insertMany([{"class" : "1", "price" : 10,"count" : 180}, { "class" : "1" ,"price" : 10,"count" : 350}, { "class" : "2" ,"price" : 10,"count" : 90}, { "class" : "2" ,"price" : 10,"count" : 320}, { "class" : "2" ,"price" : 10,"count" : 150}, { "class" : "3" ,"price" : 10,"count" : 100}, { "class" : "3" ,"price" : 10,"count" : 200}, { "class" : "3" ,"price" : 10,"count" : 300}] ) var result = db.order_2.mapReduce( // 映射函式 function() { // 計算價格和數量的乘積 var total = this.price * this.count; // 使用 "class" 作為鍵(key),將結果發射(emit)出來 emit(this.class, total); }, // 減少函式 function(key, values) { var total = 0; // 將同一鍵的所有值進行加總 for (var i = 0; i < values.length; i++) { total += values[i]; } // 返回每個 "class" 的總和 return total; }, // 選項:指定結果存儲的集合名稱為 "Test" { out: "Test", query: { class: { "$in": ["2", "3"] } }, finalize: function(key, reducedVal) { // 在最終處理階段對值進行最後處理 reducedVal = reducedVal + " dollar"; return reducedVal; } } ); // 檢索 "Test" 集合中的所有文檔 db.Test.find(); ### 牛刀小試 查詢年齡大於等於30的個數 查詢台北市的人數 查詢年齡介於20到40之間且居住在台北市的人數 查詢每個區域(district)的平均年齡 查詢台北市每個區域的人數 show dbs use mongo_class db.order_3.insertMany([ { city: "台北市", district: "北投", age: 25 }, { city: "台北市", district: "士林", age: 20 }, { city: "台北市", district: "士林", age: 30 }, { city: "台北市", district: "大同", age: 30 }, { city: "台北市", district: "大同", age: 40 }, { city: "台北市", district: "大同", age: 50 }, { city: "台北市", district: "中山", age: 15 }, { city: "台北市", district: "中山", age: 25 }, { city: "台北市", district: "松山", age: 18 }, { city: "台北市", district: "松山", age: 22 }, { city: "台北市", district: "松山", age: 35 }, { city: "台北市", district: "松山", age: 45 }, { city: "新北市", district: "板橋", age: 22 }, { city: "新北市", district: "三重", age: 45 }, { city: "新北市", district: "中和", age: 50 }, { city: "新北市", district: "永和", age: 34 }, { city: "新北市", district: "新莊", age: 45 }, { city: "新北市", district: "新店", age: 14 }, { city: "新北市", district: "土城", age: 47 }, { city: "新北市", district: "蘆洲", age: 24 }, { city: "新北市", district: "汐止", age: 35 }, { city: "新北市", district: "樹林", age: 29 }, { city: "新北市", district: "淡水", age: 43 }, { city: "新北市", district: "鶯歌", age: 24 } ]) db.order_3.count({"age":{$lt:30}}) db.order_3.count({city:"台北市"}) db.order_3.count({$and:[{"age":{$gte:20,$lte:40}},{city:"台北市"}]}) db.order_3.count({"age":{$gte:20,$lte:40},city:"台北市"})//簡化版 db.order_3.aggregate([{"$group":{"_id":"$city","total":{"$avg":"$age"}}}]) db.order_3.aggregate([{"$match":{city: "台北市"}},{"$group":{"_id":"$district","total":{$sum:1}}}]) ## 索引 優點:收尋速度快 在使用分組或排序時速度快 缺點:占空間 show dbs use mongo_class db.tests.insert({"x":"hello"}) db.tests.ensureIndex({"x":1}) db.tests.getIndexes() // 在 test_1 集合中插入 100,000 個文件 for (var i=0;i<100000;i++){db.test_1.insert({"x":i})} // 建立 x 欄位的索引 db.test_1.ensureIndex({"x":1}) // 查詢 test_1 集合中 x 大於 500,000 的文檔並進行降序排序 db.test_1.find({ "x": { "$gt": 500000 } }).sort({ "x": -1 }).explain("executionStats") // 在 test_2 集合中插入 100,000 個文件 for (var i = 0; i < 100000; i++) {db.test_2.insert({ "x": i})} // 查詢 test_2 集合中 x 大於 500,000 的文檔並進行降序排序 db.test_2.find({ "x": { "$gt": 500000 } }).sort({ "x": -1 }).explain("executionStats")