• MongoDB 入門:安裝、指令、CRUD、查詢、索引與 Map-Reduce 實作指南

Contents 目錄

什麼是MongoDB?

MongoDB-database-colection

MongoDB 是一種文件導向型數據庫,使用 BSON(Binary JSON)格式來儲存資料

每個資料庫包含多個集合(collection,=mysql table),每個集合包含了多個文檔(document),文檔是一個鍵值對(key-value pair)的 JSON 對象

  • 自由靈活 : 不需要像其他關聯式資料庫(Mysql, PostgreSQL, MSSQL)設SCHEMA,自由添加欄位,也不需要先創建表格,use database_name 後,數據可以直接 db.database_name.insertOne({})寫入
  • 支援多種複雜的數據結構 : 嵌套的文檔、數組和其他數據類型…適合處理具有多層次結構的數據
  • 良好的擴展性 : 可以水平擴展到多個節點,實現更好的性能和容量。這通常通過在集群中添加更多的機器來實現
  • 高性能 : 使用索引來實現快速查詢,支援各種類型的索引,地理、圖形、文本搜索…
  • 自動故障轉移 : 複製工具(稱為副本集)有自動故障轉移功能,提供資料的高可用性(High Availability)。

PS 在 NoSQL 數據庫中,特別是一些分佈式和高度擴展的 NoSQL 數據庫,有時會放寬對 ACID 特性的要求,以實現更高的性能和擴展性

Windows安裝MongoDB

  • 到官網上方選取 community server
    螢幕擷取畫面 2023-11-26 102131
  • 選擇要安裝的版本,下面選msi
    螢幕擷取畫面 2023-11-26 102159
  • Powershell 安裝
    螢幕擷取畫面 2023-11-26 110457

記住安裝的位置,它不像PostresSQL會自動出現Shell(psql)應用程式,之後要進資料夾找
例如我的是C:\Users\user\AppData\Local\Programs\mongosh\

開啟 mongosh.exe (powershell 介面)
螢幕擷取畫面 2023-11-26 112503

輸入預設mongodb://localhost/,進去系統後就能開始執行了

PS 要用小寫
螢幕擷取畫面 2023-11-26 113904

PS

# 返回統計信息
db.stats

螢幕擷取畫面 2023-11-27 155717

# 查看schema
typeof db.collection_name.findOne().field_name

螢幕擷取畫面 2023-11-27 155641

# runCommand 為 任意命令
# 使用 serverStatus 命令來檢索伺服器的狀態信息

var result = db.runCommand({ serverStatus: 1 });
printjson(result);

螢幕擷取畫面 2023-11-27 184251

PS MAC 安裝方法比較特別,載好後要把 /bin 裡面的兩個檔案,貼到 /mongodb/bin

  • Compass (ui介面) 如果沒自動安裝,可以手動安裝
    螢幕擷取畫面 2023-11-26 104437

PS MongoDB Database Tools 包含一系列命令行工具,但沒有特定的圖形化使用者介面(GUI)應用程式。可以通過命令行或終端來使用這些工具

mongodump: 備份
mongorestore: 用於還原從mongodump 創建的備份
mongoexport: 將 MongoDB 數據庫中的數據導出到 JSON 或 CSV 文件
mongoimport: 將 JSON、CSV 或 TSV 文件中的數據導入到 MongoDB 數據庫
mongostat: 顯示實例的統計信息
mongooplog: 回放 oplog 文件以同步數據

  • (可選) 另一種ui介面,studio 3T,滿好用的,但有限期
    studio3T_img

螢幕擷取畫面 2023-11-27 103904

JSON、BSON差異

MongoDB 表面上看起來採用JSON格式,其實背後存儲和處理數據是BSON格式

  • JSON(JavaScript Object Notation)是一種輕量級的數據交換格式,包含字符串、數字、對象、數組、布爾值和 null …基本數據類型
  • BSON(Binary JSON)是二進制 JSON 的簡稱,在 JSON 的基礎上添加了一些額外的數據類型,日期、二進制數據(例如我們會看到 “_id”:OnjectID(“…”)、正則表達式等…能更好地支持 MongoDB 數據庫

MongoDB 基礎操作

資料庫 database
資料表 collection

☑️ 資料庫 (CREATE、READ、DELETE)

# 讀取資料庫
show databases;
= show dbs

# 讀取資料表
show collections

☑️ 資料表

不用創建資料庫,只需要use資料庫
db.資料表.insert資料 進資料表後,資料庫會自動創建

mongodb的基礎CRUD

PS _id 不能重複,默認會照順序
“`=
C:
insertOne(data,options)
insertMany(data,options)

R:
find(data,options)
findOne(data,options)

U:
updateOne(filter,data,options)
updateMany(filter,data,options)
replaceOne(filter,data,options)

D:
deleteOne(filter,options)
deleteMany(filter,options)


匯入資料
```=
use test

db.test_student.insertOne({
    id: 1,
    no: '001',
    name: 'Catalina',
    phone: '0900000000',
    email: 'catalinakuowork@gmail.com'
})

讀取資料表內容

show databases

use test

show collections

db.test_student.find()
= show collections('test_student’)

# 也可以 
# 更易讀db.test_student.find().pretty()

# 也可以 
# 結果包含較大的數據集時,find()只會出現一部分,toArray()會出現全部
db.test_student.find().toArray()

PS .forEach() 方法來遍歷查詢結果的每一個文檔,通常會搭配別的軟體(Node.js,PHP…)使用

db.user.find().forEach(function(doc) {
    printjson(doc);
});

所有年齡為 68 的乘客
“`=
db.passengers.find({age:68}).name

只包含 “name” 欄位,而不包括 “_id” 欄位

db.passengers.find({ age: 68 }, { _id: 0, name: 1 })


查詢資料表內數量
```=
db.test_student.count()

前三筆

db.test_student.find().limit(3)

忽略前三筆

db.test_student.find().skip(3)

排序

db.test_student.find().sort({age:1})

刪除資料表

db.test_student.drop()

# 假設要指定條件
# db.test_student.deleteOne({id:2})

# db.test_student.deleteMany({id:2})

刪除資料庫

use test

db.dropDatabase()

查詢

$eq 等於 =

# $eq equal to
db.getCollection('test_data').find({class: {$eq:'A'}})

# 直接相等比較
= db.getCollection('test_data').find({class:'A'})

$match 篩選符合條件的文檔(等同sql where)

db.agg.aggregate([("$match":fage:($gt:10,$lte:30)))])

$or

db.getCollection('test_data').find({name:{$in:['Chad','Ethan']}})

authors 字段包含 ‘Bob’ 或 ‘hhhhh’ ,或者具有 timestamp 字段

db.getCollection("library").find({$or:[{authors:{$in:['Bob','hhhhh']}},{timestamp:{$exists:true}}]})

< >=
lt (less than)
lte (less than or equal to)

db.getCollection('test_data').find({weight:{$lt:60}})

gt (greater than)
gte (greater than or equal to)

db.getCollection('test_data').find(
    {$and:[
        {score:{$gte:80}},
        {weight:{$lt:80}}
    ]}
)

nor 不是其中之一 (不滿足以下條件之一)

db.getCollection('test_data').find(
    {$nor:[
        {class:'B'},
        {weight:{$lt:50}}
    ]}
)

= db.getCollection('test_data').find(
    {$not:{
        $or:[
            {class:'B'},
            {weight:{$lt:50}}
        ]
    }}
)

nin 都不是

db.test_data.find({class: {$nin: ['A', 'B', 'C']}})

= db.test_data.find({class: {$not: {$in: ['A', 'B', 'C']}}})

ne 不是

db.test_data.find({age: {$ne: 25}})

= db.test_data.find({age: {$not: {$eq: 25}}})

$all

用 $all 來確保 tags 陣列中包含指定的所有元素,同時我們添加了一個額外的條件

$and 來包裹一個包含兩個條件的陣列。第一個條件確保 tags 陣列等於 [“ssl”, “security”],而第二個條件確保 additionalField 的值為 “additionalValue”

db.test_data.find({tags: {$all: ["ssl", "security"]}, additionalField: "additionalValue"})

= db.test_data.find({$and: [{tags: ["ssl", "security"]}, {additionalField: "additionalValue"}]})

$size

查詢 字段 field 大小(元素的數量)為 2 的所有文檔。

db.test_data.find( { field: { $size: 2 } } )

$elemMatch,運算符用於指定一個或多個條件

results 是一個陣列,查詢 results 陣列中值大於等於 80 且小於 85

db.test_data.find( { results: { $elemMatch: { $gte: 80, $lt: 85 } } } )

查詢練習

是否有class字段的文檔

db.test_data.find(
  {class:{$exists:true}}
)

具有 class 字段且班級是 ‘B’ 或 ‘C’ 的文檔

db.test_data.find(
  {$and:[{class:{$exists:true}},{class:{$in:['B','C']}}]}
)

班級是 ‘A’ 或 ‘C’ 且分數大於等於 60 且小於 90 的文檔

db.test_data.find(
  {$and:[{class:{$in:['A','C']}},{score:{$gte:60,$lt:90}}]}
)

查詢 name 等於 “mark”,只返回符合條件的文檔中的 id 字段,同時排除 _id 字段

db.getCollection("user_likes").find({name:"mark"},{id:1,_id:0})

查詢年紀30歲(含)~60歲(不含)且fans有200人以上的人

db.getCollection("user_likes").find({$and:[{age:{$gte:30,$lt:60}},{fans:{$gte:200}}]})

# and 可以簡化
= db.getCollection("user_likes").find({age:{$gte:30,$lt:60},fans:{$gte:200}})

查詢fans在100以下(含)或likes在100以下的人(不含)

db.getCollection("user_likes").find({$or:[{likes:{$lte:100}},{fans:{$lt:100}}]})

查詢 age不為25或60的人

# nor
db.getCollection("user_likes").find({$nor:[{age:{$in:[25,26]}}]})

# not+in
= db.getCollection("user_likes").find({$not: {age: {$in: [25, 26]}}})

# nin
= db.getCollection("user_likes").find({age: {$nin: [25, 26]}})

# not nin
=
db.getCollection("user_likes").find({$not: {age: {$nin: [25, 26]}}})

查詢age不為25、60的人,並且只給我id就好

db.user_likes.find({$and:[{age:{$nin:[25,60]}}]},{_id:0,id:1})

查詢likes小於等於100的人(使用 $not)

db.getCollection("user_likes").find({likes:{$not:{$gt:100}}})

查詢$size 0 沒有任何聊天紀錄的聊天室

db.linechat.find({messages:{$size:0}})

查詢正則表達式

$regex:、$options:
查詢book字段中包含 “nosql” 字符串的文檔
PS $options:’i’ 表示不區分大小寫

db.library.find({"book":{$regex: /nosql/, $options:'i'}})
= db.library.find({"book":{$regex: 'nosql', $options: 'i'}})
= db.library.find({"book":{$regex: /nosql/i}})
= db.library.find({"book": /nosql/i})

區分大小寫

db.library.find({"book":{$regex: /nosql/, $options: ''}})
= db.library.find({"book":{$regex: 'nosql'}})
= db.library.find({"book":{$regex: /nosql/}})
= db.library.find({"book": /nosql/})

查詢正則表達式練習

查詢 messages.content 包含 “義大利麵” 的,同時排除 _id 字段

db.linechat.find({"messages.content": /義大利麵/}, {"messages.$": 1, _id: 0})

使用 $ 顯示第一個符合條件的

db.linechat.find({messages: {$elemMatch: {content: /義大利麵/}}}, {"messages.$": 1, _id: 0})

update 更新

name 為 “Mark” 的文檔的age字段設置為 18

PS 更新操作具有 “upsert” 的特性,如果原本的文檔中沒有 age 欄位,更新操作都會自動將 age 欄位添加到文檔中

db.user.updateOne({name:"Mark"},{age:18})
= db.user.updateOne({name:"Mark"},{$set:{age:18}})

age會全部被改成20

db.user.updateMany({},{$set:{age:20}})

都會成功被增加 status 狀態欄

db.flight.updateMany({},{$set : {status : {description: "on-time", lastUpdated: "1 hour ago"}}})

如果希望只有在文檔中已經存在age 欄位的情況下,才進行更新

db.user.updateOne(
   { name: "Mark", age: { $exists: true } },
   { $set: { age: 18 } }
)

將 _id 為 “4-1_1” 的文檔中的 book 字段設置為 “英語會話”

db.getCollection("library").update({"_id":"4-1_1"},{$set:{"book":"英語會話"}})

將所有 authors 字段包含 [“Tomas”,”kim”,”Biga”] 的文檔中的 authors 字段更新為 [“kim”,”Biga”]

db.getCollection("library").update({"authors":["Tomas","kim","Biga"]},{$set:{"authors":["kim","Biga"]}})

取代 replace

# 原始資料
db.test_student.insertOne({
    id: 1,
    no: '001',
    name: 'Catalina',
    phone: '0900000000',
    email: 'catalinakuowork@gmail.com'
})

db.test_student.replaceOne({id: 1},{ id: 1, no: '002', name: 'Maite', phone: '0900000000', email: 'catalinakuowork@gmail.com' })

PS 這樣會錯!

db.test_student.replaceOne({no:"001"},{name:'Maite'})

螢幕擷取畫面 2023-11-27 122057

Schema

雖然mongodb 強調的是彈性和靈活性,不需要嚴格的結構化模式,但為了防止與其他軟體交互錯誤、結構更清楚、查詢效率,很多時候還是會選擇定義一個類似模式的結構

範例

{
  "_id": ObjectId(),
  "username": "string",
  "email": "string",
  "age": "number",
  "address": {
    "street": "string",
    "city": "string",
    "zipcode": "string"
  },
  "createdAt": ISODate(),
  "updatedAt": ISODate()
}

設置時間
new Date()
new Timestamp()

螢幕擷取畫面 2023-11-27 152746

運算子

$mul 乘以 30

$set currency重新設置為 “TWD”

$currentDate lastModified 字段設置為當前日期

PS multi 選項表示更新多筆記錄,upsert 選項表示如果沒有找到符合的記錄,則不插入新的記錄

db.account.updateMany({name: "小華", "currency.type": "USD"},
{
  $mul: {"currency.$.cash": 30},
  $set: {"currency.$.type": "TWD"},
  $currentDate: {"currency.$.lastModified": {$type: "date"}}
},
{multi: true, upsert: false})

$rename 改名

所有的studentNumber都改成studentId

db.school.updateMany({},{$rename:{"studentNumber":"studentId"}})

指定小明,studentNumber改成studentId

db.school.updateOne({studentName: "小明"},{$rename:{"studentNumber":"studentId"}})

$push 更新陣列運算子

增加一筆資料在最後面

# 原始
db.user.insertOne({ "name" : "mark", "fans" : ["steven","crisis","stanly"] })

# 增加資料
db.user.updateOne({"name":"mark"}, {$push:{"fans":"jack"}})
db.flights.updateOne({id:1}, {$push:{today:new Date()}})

$each 更新陣列運算子

增加多筆資料在最後面

# 原始
db.user.insertOne({ "name" : "mark", "fans" : ["steven","crisis","stanly"] })

# 增加資料
db.user.updateOne({"name":"mark"}, {$push:{"fans":{$each:["jacky","Inadry","max"]}}})

$slice 保留陣列的固定數量

# 原始
db.user.insertOne({ "name" : "mark", "fans" : ["steven","crisis","stanly"] })

# 保留 fans 陣列的前 2 個元素,刪除多餘的元素。因此包含 "jacky""Inadry",不包含 "max" 
db.user.updateOne({"name":"mark"}, {$push:{"fans":{$each:["jacky","Inadry","max"],$slice: 2}}})
# 原始
db.user.insertOne({ "name" : "mark", "fans" : ["steven","crisis","stanly"] })

# 增加"jacky","Inadry","max"後,保留 fans 陣列的後 4 個元素,刪除多餘的元素。因此包含 "stanly","jacky","Inadry","max",不包含 "steven","crisis"
db.user.updateOne({"name":"mark"}, {$push:{"fans":{$each:["jacky","Inadry","max"],$slice: -4}}})

$addToSet 保留不重複資料

# 原始
db.user.insertOne({ "name" : "mark", "fans" : ["steven","crisis","stanly"] })

# 會出現 "steven","crisis","stanly","jack","peter"
db.user.updateOne({"name":"mark"},{$addToSet:{fans:{$each:["steven","jack","peter"]}}})

$pull 把相符的值都拉走(刪除)

db.fruit.updateOne({"name": "John"}, {$pull: {likes: "apple"}})

= db.fruit.updateOne({ "name": "John" },{ "$pull": { "likes": { "$in": ["apple"] } } })

$unset

假設想要將 John 的 likes 屬性中的所有元素都刪除

可以使用 $unset 將 likes 屬性刪除

db.fruit.updateMany(
  { "likes": { "$exists": true } }, 
  { "$unset": { "likes": "" }}
)

但是如果 likes 屬性不是所有文件中都存在,則需要使用 $pull 搭配 $exists 來實現

首先使用 $exists 找出所有存在 likes 屬性的文件,之後把like清空

db.fruit.updateMany(
{ "likes": { "$exists": true } },
{ "$pull": { "likes": { "$exists": true } } }
)

$max

分數不得低於60,若低於60,變成60

db.school.updateMany({},{$max:{score:NumberInt(60)}})

= db.school.updateMany({score: {$lt: 60}}, {$set: {score: 60}})

$pop 刪除陣列的第一個或最後一個元素。第一個元素(1)或最後一個元素(-1)

db.user.updateOne({"name":"mark"},{"$pop":{"fans":1}})

$inc 增加或減少數字型欄位的值

# 向 log 陣列中推送一個包含 datesize 的新物件

# { upsert: false } 如果找不到匹配的文檔,不創建新文檔

db.drink.updateOne(
  { "_id": "001" },
  {
    $inc: { "sold": 20 },
    $push: { "log": { date: Date.now(), size: "M" } }
  },
  { upsert: false }
)

$regex $sort

#  找到陳 0955 開頭的人,age排序
db.user.find(
  {
    $and: [
      { name: { $regex: /陳/ } },
      { phone: { $regex: /0955/ } }
    ]
  }
).sort({ age: 1 })

= db.user.find((name:($regex:/陳/),phone:($regex:/0955/)).sort(age:1)

aggregate

$sort 由小到大 1 由大到小 -1

db.agg.aggregate([{ $sort: { age: 1 }}])

= db.agg.find({}).sort({ age: 1 })

$project 對結果進行投影 1 True, 0 False

# 原始
db.agg.insertMany([
  { "id": 1, "name": "mark", "age": 20, "assets": 100000000 }])


# 聚合操作
db.agg.aggregate([{ $project: { id: 1, name: 1 } }])
= db.agg.find({}, { _id: 0, id: 1, name: 1 })

$match 篩選符合條件的文檔(等同sql where)

db.agg.aggregate([("$match":age:($gt:10,$lte:30)))])
= db.agg.find({ age: {$gt:10, $lte:30 }})

$group 分組

# 原始
use testing
db.ox.insertMany(("id" :1 , "status" : "o", "count" : 5})
db.ox.insert(f"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.distinct("status")

螢幕擷取畫面 2023-11-26 182206

$group 分組,自定義a、b欄位

db.ox.aggregate([("$group":(_id: (a:"$status", b:"$count")))])

螢幕擷取畫面 2023-11-26 180253

$group 分組,sum = 將count的值相加

db.ox.aggregate([("$group":(_id:"$status", total: ("$sum": "$count")))])

螢幕擷取畫面 2023-11-26 180218

$unwind 展開陣列字串
1700993034149

db.agg2.aggregate([("$unwind" : "$fans")])
= db.agg2.find({}, {fans: 1, _id: 0 })

螢幕擷取畫面 2023-11-26 180436

$limit

db.agg.aggregate([{ $limit: 10 }])
= db.agg3.find({}).limit(10)

$skip

# 跳過結果集中的前 5 個文檔
db.agg.aggregate([{ $skip: 5 }])
= db.agg.find({}).skip(5)

$lookup

db.orders.insertMany([
  { _id: 1, customerId: "C1", amount: 50 },
  { _id: 2, customerId: "C2", amount: 75 },
  { _id: 3, customerId: "C1", amount: 30 }
]);

db.customers.insertMany([
  { _id: "C1", name: "Alice" },
  { _id: "C2", name: "Bob" }
]);

使用 $lookup 進行關聯

db.orders.aggregate([
  {
    $lookup: {
      from: "customers",           // 要關聯的集合名稱
      localField: "customerId",    // 本地集合的字段
      foreignField: "_id",         // 外來集合的字段
      as: "customerInfo"           // 聯合結果的新字段名稱
    }
  }
]);

螢幕擷取畫面 2023-11-27 182324

運算子練習

增加 80
增加 [80,50,60]
刪除最後一筆

show dbs
use school
db.school.insertOne([_id:"001", , list: [30, 40, 50]])
db.school.updateOne((_id:"001"), ($push:("list":80)))
db.school.updateMany((_id:"001"),($push:("list":($each:[80,50,60]))))
db.school.updateMany((_id:"001"),("$pop":("list":-1))
db.school.find()

螢幕擷取畫面 2023-11-26 173840

$group,然後按 _id升序排序,再跳過前 5 個結果

db.agg.aggregate([
{ $group: { _id: { a: "$status", b: "$count" } } },
{ $sort: { "_id": 1 } }, 
{ $skip: 5 }
])

找第二年輕的男生

db.agg.aggregate([{$match:{sex:"M"}},{$sort:{age:1}},{$skip:1},{$limit:1}])

加上{ $project: {name:1, age:1}},只投影name、age

db.agg.aggregate([{$match:{sex:"M"}},{$project:{name:1, age:1}},{$sort:{age:1}},{$skip:1},{$limit:1}])

數據結構 (嵌套文檔、數組)

使用嵌套文檔,address 是一個包含 street 和 city 字段的子文檔。這種方式適用於表示一個完整的地址信息,並且可以方便地查詢整個地址

{ id: "001", username: "catalina", address: { street: 'bade st', city: 'taipei' } }

使用了數組,address 是一個包含兩個元素的數組,每個元素都是包含一個字段的子文檔。這種方式適用於表示部分地址信息,每個元素可以單獨地表示一個地址的一部分。

數組(Array)通常包含多個相似值的集合,而使用物件(Object)來表示鍵值對

{ id: "001", username: "catalina", address: [{ street: 'bade st' }, { city: 'taipei' }] }

Relationship 關係

在 MongoDB 中,數據之間的關係通常是透過嵌套文檔(Nested Documents, Embedded)或引用(References)來實現的

ONE TO ONE

嵌套文檔(Nested Documents, Embedded)

# 兩個collections
db.patients.insertOne({name:"Catalina", age:"26", diseaseSummary:"summary-max-1"})

db.diseaseSummaries.insertOne({id:"summary-max-1", diseases:["cold","covid"]})

定義變數

var dsid = db.patients.findOne().diseaseSummary

螢幕擷取畫面 2023-11-27 164741

查詢

db.diseaseSummaries.findOne({id:dsid})

螢幕擷取畫面 2023-11-27 164818

引用(References),使用ObjectId(“…”)

# 一個collection 插入購買者+車子資訊、購買者+個人資訊
db.person.insertOne({name:"catalina",car:{model:"bmw",price:40000}})

db.person.insertOne({name:"catalina",age:26, salary:50000)

螢幕擷取畫面 2023-11-27 170159

插入引用

db.person.insertOne({model:"bmw", price:40000, owner: ObjectId('65645a027ed280d551a4fb2b')})

螢幕擷取畫面 2023-11-27 170249

ONE TO MANY

嵌套文檔(Nested Documents, Embedded)

db.questionThreads.insertOne({
  creator: "catalina",
  question: "How is it going?",
  answers: [
    { _id: "q1a1" },
    { _id: "q1a2" }
  ]
});

db.answers.insertMany([{_id: "q1a1", text: "nice"}, {_id: "q1a2", text: "awesome!"}])

定義變數

var questionThreadId = db.questionThreads.findOne()._id;

查詢

db.answers.find({ _id: { $in: db.questionThreads.findOne().answers.map(a => a._id) } })

嵌套文檔(Nested Documents, Embedded)

db.questionThreads.insertOne({
  creator: "catalina",
  question: "How is it going?",
  answers: [
    { _id: "q1a1" },
    { _id: "q1a2" }
  ]
});

db.answers.insertMany([{_id: "q1a1", text: "nice"}, {_id: "q1a2", text: "awesome!"}])

插入

db.questionThreads.insertOne({creator:"catalina",question: 'How is it going?',answers: [ {text: 'nice'},{text: 'awesome!'}]})

螢幕擷取畫面 2023-11-27 175959

引用(References),使用ObjectId(“…”)

插入引用

db.cities.insertOne({name: "New York City", coordinates: {lat: 21, llng:55}})

# 出現的 ObjectId,貼到下面
db.citizens.insertMany([{name:"catalina",cityId: ObjectId("65646a337
ed280d551a4fb31")}, {name : "Eva", cityId: ObjectId("65646a337ed280d551a4fb31")}
])

螢幕擷取畫面 2023-11-27 181247

螢幕擷取畫面 2023-11-27 181334

查詢

db.citizens.find()

螢幕擷取畫面 2023-11-27 181107

MANY TO MANY

嵌套文檔(Nested Documents, Embedded)

db.products.insert({title:"book", price:"12.22"})

db.customers.insert({name:"catalina", age:26})

更新 customers表

db.customers.updateMany( { $or: [{ name: "Tomas" }, { name: "catalina" }] }, { $set: { orders: [{ productId: ObjectId('656480076e814db5173266c4'), quantity: 5 }] } } );

引用(References),使用ObjectId(“…”)

少用~ 兩邊數據都要改,很容易出錯

Map-Reduce 操作

map: map函數.主要功能為產生key給reduce

reduce:reduce函數

out: 輸出結果集合的名稱

query: 在map前,可用query先進行篩選

sort: 在map前.可用sort進行排序

limit: 在map前,可限制數量

finalize: 可以將reduce的結果丟給某個key

scope: 可以在is中使用變數

求id 1 2

螢幕擷取畫面 2023-11-26 184203

# 計算每個 class 的總價(price * count),並將結果存儲在 "mapReduceTest" 這個結果集合中
var result = db.order.mapReduce(
function(){
var total = this.price * this.count
emit(this.class,total)
},
function(key,values )(
var total = 0;
for(var i=0;i<values.length;i++)
(total+=values[i];
}
return total;
},
{out : "mapReduceTest"}
)

螢幕擷取畫面 2023-11-26 184232

id 2 3 + dollar

螢幕擷取畫面 2023-11-26 184308

var result = db.order_2.mapReduce(
function(){
    var total = thos.price * this.count
    emit(this.class, total)
},
function(key,values){
    var total = 0;
    for(var i=0;i<values.length;i++){
total += values[i];
}
    return total;
},
{out: "test",
    query:(class:("$in":["2","3"])),
    finalize:function(key, reducedVal){
        reducedVal = reducedVal + "dollar";
            return reducedVal;
    }
}
)

設置索引(加速對集合中數據的查詢,但較耗容量)

通常會使用在

  • 查詢頻繁的字段
  • 聚合、排序和分組操作
  • 唯一性要求
  • 模糊查詢

一般用法,沒設索引

db.tests.insertOne({ "x": "hello" })

有設索引

db.tests.createIndex({ "x": 1 })
= db.tests.ensureIndex({ "x": 1 })

防止錯誤
如果輸入不符合createCollection定義的規則會錯誤

db.createCollection('exampleCollection', {
  validator: {
    $jsonSchema: {
      bsonType: 'object',
      required: ['field1', 'field2'],
      properties: {
        field1: {
          bsonType: 'string',
          description: '必須是一個字符串'
        },
        field2: {
          bsonType: 'number',
          description: '必須是一個數字'
        }
      }
    }
  }
});

設置索引練習

  • 練習一
    設索引 {age:1,name:1} 會比較快
    “`=
    db.user_1.ensureIndex({name:1,age:1})
    db.user_2.ensureIndex({age:1,name:1})

db.user_1.find({}).sort({age:1})
db.user_2.find({}).sort({age:1})


<br/>

- 練習二

一般用法,沒設索引
    使用 for 迴圈插入 100,000 條數據到 test_2 集合

    使用 find 查詢 "x" 大於 50,000 的數據,然後使用 sort 將結果按 "x" 字段降序排列,最後使用 explain 顯示查詢的執行統計信息
```=
for (var i = 0; i < 100000; i++) {
    db.test_2.insertOne({ "x": i });
}

db.test_2.find({ "x": { "$gt": 50000 } }).sort({"x": -1}).explain("executionStats");

設索引
在test_2 集合的 “x” 字段上創建一個升序索引

for (var i = 0; i < 100000; i++) {
    db.test_2.insertOne({ "x": i });
}

db.test_2.ensureIndex({"x": 1});

db.test_2.find({ "x": { "$gt": 50000 } }).sort({"x": -1}).explain("executionStats");
Catalina
Catalina

Hi, I’m Catalina!
原本在西語市場做開發業務,2023 年正式轉職資料領域。
目前努力補齊計算機組織、微積分、線性代數與機率論,忙碌中做點筆記提醒自己 🤲

文章: 43

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *