帶你走進MongoDB

来源:https://www.cnblogs.com/value-code/archive/2018/01/15/8288303.html
-Advertisement-
Play Games

一、簡介 MongoDB是一款強大、靈活、且易於擴展的通用型資料庫 1、易用性 1)MongoDB是一款面向文檔的資料庫,而不是關係型資料庫,因此而有著更好的擴展性。 2)通過在文檔中嵌入文檔和數組,面向文檔的方法能夠僅使用一條記錄來表現複雜的層級關係。 3)MongoDB沒有預定義模式(prede ...


一、簡介

  MongoDB是一款強大、靈活、且易於擴展的通用型資料庫

  1、易用性

    1)MongoDB是一款面向文檔的資料庫,而不是關係型資料庫,因此而有著更好的擴展性。

    2)通過在文檔中嵌入文檔和數組,面向文檔的方法能夠僅使用一條記錄來表現複雜的層級關係。

    3)MongoDB沒有預定義模式(predefined schema):文檔的鍵和值不再有固定的類型和大小;這樣沒有固定的模式,添加或刪除欄位就變得容易了。    

    4)使用MongoDB開發時能夠進行快速迭代,所以開發進程得以加快。

  2、易擴展性

    PS:當數據量不斷增長,增長到存儲極限時,就需要擴展資料庫了;資料庫的擴展分為縱向擴展和橫向擴展:縱向擴展就是使用性能更好的機器,

      橫向擴展就是使用更多的機器。

    1)MongoDB的設計採用橫向擴展,它能很容易的在多台伺服器之間進行數據分割

    2)MongoDB能夠自動處理跨集群的數據和負載,自動重新分配文檔,並將用戶的請求路由到正確的機器上。

  3、豐富的功能

    1)索引

      - 支持通用二級索引,允許多種快速查詢,且提供唯一索引、複合索引、地理空間索引、全文索引

    2)存儲JavaScript

      - 開發人員可以直接在服務端存取JavaScript的函數和值

     3)聚合

      - 支持聚合管道,用戶能通過簡單的片段創建複雜的集合,並通過資料庫自動優化

    4)特殊的集合類型

      - 支持存在時間有限的集合,適用於那些將在某個時刻過期的數據,如會話session。類似地,MongoDB也支持固定大小的集合,用於保存近期數據,如日誌。

    5)文件存儲

      - 支持一種非常易用的協議,用於存儲大文件和文件元數據。MongoDB並不具備一些在關係型資料庫中很普遍的功能,如鏈接join和複雜的多行事務。省略

         這些的功能是處於架構上的考慮,或者說為了得到更好的擴展性,因為在分散式系統中這兩個功能難以高效地實現。

  4、卓越的性能

    1)MongoDB把儘可能多的記憶體用作緩存cache,視圖為每次查詢自動選擇正確的索引。

    2)只要有可能,資料庫伺服器就會將處理邏輯交給客戶端。這種精簡方式的設計是MongoDB能夠實現如此高性能的原因之一。

二、MongoDB基礎知識

  1、文檔是MongoDB的核心概念。文檔就是鍵值對的一個有序集{'msg':'hello','foo':3}。類似於python中的有序字典。

需要註意的是:
#1、文檔中的鍵/值對是有序的。
#2、文檔中的值不僅可以是在雙引號裡面的字元串,還可以是其他幾種數據類型(甚至可以是整個嵌入的文檔)。
#3、MongoDB區分類型和大小寫。
#4、MongoDB的文檔不能有重覆的鍵。
#5、文檔中的值可以是多種不同的數據類型,也可以是一個完整的內嵌文檔。文檔的鍵是字元串。除了少數例外情況,鍵可以使用任意UTF-8字元。

文檔鍵命名規範:
#1、鍵不能含有\0 (空字元)。這個字元用來表示鍵的結尾。
#2、.和$有特別的意義,只有在特定環境下才能使用。
#3、以下劃線"_"開頭的鍵是保留的(不是嚴格要求的)。

  2、集合就是一組文檔。如果將MongoDB中的一個文檔比喻為關係型數據的一行,那麼一個集合就是相當於一張表

      1)集合存在於資料庫中,為了管理方便,我們應該將不同格式和類型的數據插到不同的集合,但集合併沒有固定的結構,

      也就意味著我們完全可以把不同格式和類型的數據插入到同一個集合中。

    2)使用“.”組織子集合

       比如一個具有博客功能的應用可能包含兩個集合,分別是blog.posts和blog.authors,這是為了使組織結構更清晰,

       這裡的blog集合(這個集合甚至不需要存在跟它的兩個子集合沒有任何關係;在MongoDB中,使用子集合來組織數據非常高效,值得推薦。

    3)當第一個文檔插入時,集合就會被創建。合法的集合名:

      - 集合名不能是空字元串""。

      - 集合名不能含有\0字元(空字元),這個字元表示集合名的結尾。

      - 集合名不能以"system."開頭,這是為系統集合保留的首碼。

       - 用戶創建的集合名字不能含有保留字元。

  3、資料庫:在MongoDB中,多個文檔組成集合,多個集合可以組成資料庫

資料庫也通過名字來標識。資料庫名可以是滿足以下條件的任意UTF-8字元串:
#1、不能是空字元串("")。
#2、不得含有' '(空格)、.、$、/、\和\0 (空字元)。
#3、應全部小寫。
#4、最多64位元組。

有一些資料庫名是保留的,可以直接訪問這些有特殊作用的資料庫。
#1、admin: 從身份認證的角度講,這是“root”資料庫,如果將一個用戶添加到admin資料庫,這個用戶將自動獲得所有資料庫的許可權。
  再者,一些特定的伺服器端命令也只能從admin資料庫運行,如列出所有資料庫或關閉伺服器
#2、local: 這個資料庫永遠都不可以複製,且一臺伺服器上的所有本地集合都可以存儲在這個資料庫中 #3、config: MongoDB用於分片設置時,分片信息會存儲在config資料庫中

   4、強調:把資料庫名添加到集合名前,得到集合的完全限定名,即命名空間

    - 例如:

      如果要使用cms資料庫中的blog.posts集合,這個集合的命名空間就是

       cmd.blog.posts。命名空間的長度不得超過121個位元組,且在實際使用中應該小於100個位元組
三、基本數據類型

    1、在概念上,MongoDB的文檔與Javascript的對象相近,因而可以認為它類似於JSON。JSON(http://www.json.org)是一種簡單的數據表示方式:

       其規範僅用一段文字就能描述清楚(其官網證明瞭這點),且僅包含六種數據類型。

    2、這樣有很多好處:易於理解、易於解析、易於記憶。然而因為只有null、布爾、數字、字元串、數字和對象這幾種數據類型,

       所以JSON的表達能力有一定的局限。

    3、雖然JSON具備的這些類型已經具有很強的表現力,但絕大數應用(尤其是在與資料庫打交道時)都還需要其他一些重要的類型。

          例如,JSON沒有日期類型,這使得原本容易的日期處理變得麻煩。另外,JSON只有一種數字類型,無法區分浮點數和整數,更別說區分32位和64位了。

       再者JSON無法表示其他一些通用類型,如正則表達式或函數。

    4、MongoDB在保留了JSON基本鍵/值對特性的基礎上,添加了其他一些數據類型。在不同的編程語言下,這些類型的確切表示有些許差異。

       下麵說明瞭MongoDB支持的其他通用類型,以及如何在文檔中使用它們:

#1、null:用於表示空或不存在的欄位
d={'x':null}
#2、布爾型:true和false
d={'x':true,'y':false}
#3、數值
d={'x':3,'y':3.1415926}
#4、字元串
d={'x':'egon'}
#5、日期
d={'x':new Date()}
d.x.getHours()
#6、正則表達式
d={'pattern':/^egon.*?nb$/i}

正則寫在//內,後面的i代表:
i 忽略大小寫
m 多行匹配模式
x 忽略非轉義的空白字元
s 單行匹配模式

#7、數組
d={'x':[1,'a','v']}

#8、內嵌文檔
user={'name':'egon','addr':{'country':'China','city':'YT'}}
user.addr.country

#9、對象id:是一個12位元組的ID,是文檔的唯一標識,不可變
d={'x':ObjectId()}

    5、_id和ObjectId

五、CRUD操作

  1、資料庫操作

#1、增
use config #如果資料庫不存在,則創建資料庫,否則切換到指定資料庫。

#2、查
show dbs #查看所有
要想顯示出剛創建的資料庫,我們需要向資料庫插入一些數據。
db.table1.insert({'a':1})

#3、刪
use config #先切換到要刪的庫下
db.dropDatabase() #刪除當前庫

 

  2、集合操作

#1、增
當第一個文檔插入時,集合就會被創建
> use database1
switched to db database1
> db.table1.insert({'a':1})
WriteResult({ "nInserted" : 1 })
> db.table2.insert({'b':2})
WriteResult({ "nInserted" : 1 })

#2、查
> show tables
table1
table2

#3、刪
> db.table1.drop()
true
> show tables
table2

  3、文檔操作

  

#創建一個user的局部變數,這是一個JavaScript對象
user={
    "name":"ming",
    'is_nb':true,
    'hobbies':['music','read','game']
}

db.userinfo.insert(user)
db.userinfo.find()


user1={
    "name":"asb",
    'is_sb':true,
    'hobbies':['music','sports']
}
user2={
    "name":"egon",
    'is_sb':'wxx',
    'hobbies':['music','read','dancing']
}

user3={
    "name":"alex",
    'is_sb':false,
    'hobbies':['music','read','girls']
}
db.userinfo.insertMany([user1,user2,user3]) #一次插入多個文檔

   

複製代碼
update() 方法用於更新已存在的文檔。語法格式如下:
db.collection.update(
   <query>,
   <update>,
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   }
)
參數說明:對比update db1.t1 set name='EGON',sex='Male' where name='egon' and age=18;

query : 相當於where條件。
update : update的對象和一些更新的操作符(如$,$inc...等,相當於set後面的
upsert : 可選,預設為false,代表如果不存在update的記錄不更新也不插入,設置為true代表插入。
multi : 可選,預設為false,代表只更新找到的第一條記錄,設為true,代表更新找到的全部記錄。
writeConcern :可選,拋出異常的級別。

更新操作是不可分割的:若兩個更新同時發送,先到達伺服器的先執行,然後執行另外一個,不會破壞文檔。
update用法介紹
#1、最簡單的更新就是用一個新的文檔完全替換匹配的文檔。這適用於大規模式遷移的情況。例如對下麵的用戶文檔做
一個比較大的調整
> db.user.find().pretty()
{
    "_id" : ObjectId("5a5b3a74c126b4b2cbb57e3f"),
    "name" : "ming",
    "girl_friends" : 20,
    "height" : 170
}


# 先找到要修改的對象
> var obj=db.user.findOne({'name':'ming'})
> obj
{
    "_id" : ObjectId("5a5b3a74c126b4b2cbb57e3f"),
    "name" : "ming",
    "girl_friends" : 20,
    "height" : 170
}
# 修改
> obj.detail={'girl_friends':20,'height':170}
{ "girl_friends" : 20, "height" : 170}
> obj.username=obj.name
egon

# 刪掉不要的
> delete obj.girl_friends
true
> delete obj.height
true
> delete obj.name
true

# 完成更新
> db.user.update({'name':'ming'},obj)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5a5b3a74c126b4b2cbb57e3f"), "detail" : { "girl_friends" : 20, "height" : 170}, "username" : "ming" }
簡單更新
2、一個常見的錯誤
db.user.insert({'name':'ming','age':10})
db.user.insert({'name':'ming','age':20})
db.user.insert({'name':'ming','age':30})
> db.user.find()
{ "_id" : ObjectId("5a5b3ecac126b4b2cbb57e43"), "name" : "ming", "age" : 10 }
{ "_id" : ObjectId("5a5b3ecbc126b4b2cbb57e44"), "name" : "ming", "age" : 20 }
{ "_id" : ObjectId("5a5b3ecdc126b4b2cbb57e45"), "name" : "ming", "age" : 30 }

# 找到的是第二個ming,他要過生日,於是長了一歲
> var obj=db.user.findOne({'name':'ming','age':20})
> obj.age++


# 我們的條件只定位到第二條記錄這一條記錄,所以更新是沒問題的,
> db.user.update({'name':'ming','age':20},obj)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

# 我們的條件定位到了多條記錄,而obj對象的_id是一定的,文檔中的_id是唯一的,我們無法將三條改成同一個_id,所以報錯
> db.user.update({'name':'ming'},obj) #報錯

# 刪掉後,更新成功,但預設改的是第一條
> delete obj._id
true
> obj
{ "name" : "ming", "age" : 21 }
> db.user.update({'name':'ming'},obj)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5a5b40f6c126b4b2cbb57e46"), "name" : "ming", "age" : 21 }
{ "_id" : ObjectId("5a5b40f6c126b4b2cbb57e47"), "name" : "ming", "age" : 20 }
{ "_id" : ObjectId("5a5b40f6c126b4b2cbb57e48"), "name" : "ming", "age" : 30 }
> 

# 所以針對這種情況,我們還以_id作為條件保證只定位到我們想要修改的對象,並且比起隨機字元串,_id的查找速度更快
> db.user.update({'_id':ObjectId("5a5b40f6c126b4b2cbb57e47")},obj)

# ps: 改多條
> db.user.update({'name':'ming'},obj,{'multi':true})
WriteResult({
    "nMatched" : 0,
    "nUpserted" : 0,
    "nModified" : 0,
    "writeError" : {
        "code" : 9,
        "errmsg" : "multi update only works with $ operators" #只能用修改器
    }
})
> db.user.update({'name':'ming'},{$set:obj},{'multi':true})
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 1 })
一個常見的錯誤
通常文檔只會有一部分需要更新。可以使用原子性的更新修改器,指定對文檔中的某些欄位進行更新。
更新修改器是種特殊的鍵,用來指定複雜的更新操作,比如修改、增加後者刪除

#=======>1、"$set"修改器
> db.user.find()
{ "_id" : ObjectId("5a5b51a257147a04b81f2bb4"), "name" : "egon", "age" : 10 }
{ "_id" : ObjectId("5a5b51a257147a04b81f2bb5"), "name" : "egon", "age" : 20 }
{ "_id" : ObjectId("5a5b51a357147a04b81f2bb6"), "name" : "egon", "age" : 30 }
#完全覆蓋原文檔
> db.user.update({'_id':ObjectId("5a5b51a257147a04b81f2bb4")},{'age':111})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5a5b51a257147a04b81f2bb4"), "age" : 111 }
{ "_id" : ObjectId("5a5b51a257147a04b81f2bb5"), "name" : "egon", "age" : 20 }
{ "_id" : ObjectId("5a5b51a357147a04b81f2bb6"), "name" : "egon", "age" : 30 }
>

#$set只更新原文檔的一部分
> db.user.update({'_id':ObjectId("5a5b51a257147a04b81f2bb5")},{'$set':{'age':222}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5a5b51a257147a04b81f2bb4"), "age" : 111 }
{ "_id" : ObjectId("5a5b51a257147a04b81f2bb5"), "name" : "egon", "age" : 222 }
{ "_id" : ObjectId("5a5b51a357147a04b81f2bb6"), "name" : "egon", "age" : 30 }

# 有則更新,無則新增
> db.user.update({'age':30},{'$set':{'addr':{'country':'China','city':'BJ'}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5a5b51a257147a04b81f2bb4"), "age" : 111 }
{ "_id" : ObjectId("5a5b51a257147a04b81f2bb5"), "name" : "egon", "age" : 222 }
{ "_id" : ObjectId("5a5b51a357147a04b81f2bb6"), "name" : "egon", "age" : 30, "addr" : { "country" : "China", "city" : "BJ" } }


# 修改內嵌文檔
db.user.update({'age':30},{'$set':{'addr.country':'CHINA'}})

# $unset 刪除該鍵值對
db.user.update({'age':30},{'$unset':{'addr':'什麼值都行'}})



#=======>2、增加和減少
"$inc"修改器用來增加已經有的鍵的值(負數則為減少),或者該鍵不存在那就創建一個。只能用於整型、長整型或雙浮點
的值。
對於更新分析數據、因果關係、投票或者其他有變化數值的地方,使用這個都會非法方便


例如:
> db.analytics.find()
{ "_id" : ObjectId("5a5b4cb2126d610970c553ab"), "url" : "http://www.baidu.com", "pv" : 2 }
> db.analytics.update({'url':'http://www.baidu.com'},{'$inc':{'pv':1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.analytics.find()
{ "_id" : ObjectId("5a5b4cb2126d610970c553ab"), "url" : "http://www.baidu.com", "pv" : 3 }
使用修改器時,_id的值不能改變。其他的鍵值,包括其他的唯一索引的鍵,都是可以更改的。
註意:整個文檔替換時可以改變_id



#=======>3、往數組內添加元素
如果數組已經存在,"$push"會向已有的數組末尾加入一個元素,要是沒有就創建一個新的數組。
例如提交博客的評論

db.blog.insert({'_id':1,'name':'alex意外死亡的真相'})

db.blog.update({'_id':1},{'$push':{'comments':{"name":"egon","content":'alex是誰???'}}})
db.blog.update({'_id':1},{'$push':{'comments':{"name":"wxx","content":'我去,真的假的'}}})
db.blog.update({'_id':1},{'$push':{'comments':{"name":"yxx","content":'吃喝嫖賭抽,欠下兩個億'}}})

> db.blog.find().pretty()
{
        "_id" : 1,
        "name" : "alex意外死亡的真相",
        "comments" : [
                {
                        "name" : "egon",
                        "content" : "alex是誰???"
                },
                {
                        "name" : "wxx",
                        "content" : "我去,真的假的"
                },
                {
                        "name" : "yxx",
                        "content" : "吃喝嫖賭抽,欠下兩個億"
                }
        ]
}


              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 題記 對於top命令來說,基本是都是linux命令入門中,第一個使用的命令,在windows中電腦如果卡頓,回去任務欄中查看cpu和記憶體的使用情況。top命令實現的就是這個重要的功能。 在系統維護的過程中,隨時可能有需要查看 CPU 使用率,並根據相應信息分析系統狀況的需要。在 CentOS 中,可 ...
  • 1.兩個字典:a={'a':1,'b':2,'c':3} b= {'aa':11,'bb':22,'cc':33} 合併1:dict(a, b) 操作如下: a={'a':1,'b':2,'c':3} b= {'aa':11,'bb':22,'cc':33} dict(a, b) {'a': 1, ...
  • 埠名稱 埠號/協議 別名 ftp 21/tcp Telnet 23/tcp smtp 25/tcp mail nicename 43/tcp whois domain 53/tcp nameserver domain 53/udp nameserver finger 79/tcp http 80 ...
  • awk是一個強大的文本分析工具,相對於grep的查找,sed的編輯,awk在其對數據分析並生成報告時,顯得尤為強大。簡單來說awk就是把文件逐行的讀入,以空格為預設分隔符將每行切片,切開的部分再進行各種分析處理。 awk有3個不同版本: awk、nawk和gawk,未作特別說明,一般指gawk,ga ...
  • 1、思科設備和微軟系統整合的背景: 公司內部有一定數量的客戶端,為了實現統一化,在管理內部部署了域架構,這樣可以通過組策略對客戶端進行批量化管理,提高了管理的效率。 同樣公司內部有一定數量的網路設備(交換機,路由器,防火牆等),在遠程管理的時候是通過Telnet方式。 在本案例中,希望用戶遠程管理網 ...
  • [譯註]翻譯這篇文章,主要是覺得老外在思考問題時,勇於打破固有的技術棧積累,嘗試不同的選擇,從而找到最合適自己的技術方案、得到真正的實惠。 Synergy SKY提供多種軟體解決方案,本文想討論的是關於一套用於視頻相關的呼叫記錄(CDR)分析解決方案。 為客戶提供方案時有兩種選擇,一是讓客戶避免所有 ...
  • 處理MySQL的ibdata1文件過大問題 本人遇到一次在安裝zabbix監控的時候,yum安裝的MySQL資料庫,後面用了一段時間發現data目錄下的ibdata1的空間特別大,反而我的zabbix資料庫的空間很小,這樣的情況在後面備份zabbix資料庫的時候會很不方便,所以想著要怎麼解決下。 i ...
  • 今天客戶提了一個小需求,希望我能提供一條sql語句,幫助他對數據中 _field 這個欄位的值去重,並且保留其他欄位的數據。第一反應是select distinct,但這種語句在對某個欄位去重時,無法保留其他欄位,所以select distinct不成立。因為用戶對去重沒有要求,欄位值重覆時保留任意 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...