MongoDB - 增刪改查

来源:https://www.cnblogs.com/fatedeity/archive/2022/11/16/16894865.html
-Advertisement-
Play Games

對於開發人員而言,資料庫的增刪改查操作才是最常使用的功能,學習 MongoDB 時還需對這些功能熟記於心才行啊。我就在這裡做一個簡單的備忘,多看官方文檔才是正道。 ...


連接

標準 URI 連接語法

通常,可以設定標準的 URI 連接語法,作為連接配置:

mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
  • mongodb://: 固定的格式,即指定當前的 URI 是標準的 MongoDB 連接語法
  • username:password@: 可選項,如果設置,在連接資料庫伺服器之後,驅動會嘗試登錄這個資料庫
  • host1: 必須的,至少指定一個 host,它指定了要連接伺服器的地址。如果要連接副本及集,需要指定多個主機地址
  • portX: 可選的指定埠,如果不填,預設為 27017
  • /database: 如果指定賬號和密碼,連接並驗證登錄指定資料庫。若不指定,預設打開 test 資料庫
  • ?options: 連接選項,如果沒有指定資料庫,則前面需要加上 /。所有連接選項都是鍵值對 name=value,鍵值對之間通過 &; 隔開

連接選項

標準的連接格式包含了多個選項,如下所示:

  • replicaSet=name: 驗證副本集的名稱
  • slaveOk=true|false: 選擇連接主伺服器的方式
    • true: 表示有從伺服器,當 connect=direct 時會連接第一臺機器,即使這台不是主伺服器;當 connect=replicaSet 時會發送所有的寫請求到主並且把讀請求分佈在其他從伺服器
    • false: 表示無從伺服器,當 connect=direct 時會自動找尋主伺服器;當 connect=replicaSet 時僅連接主伺服器,並且所有的讀寫命令都連接到主伺服器
  • safe=true|false: 設置為 true 時,在執行更新操作之後,驅動都會發送 getLastError 命令來確保更新成功
  • w=n: 驅動添加 {w: n}getLastError 命令,應用於 safe=true
  • wtimeoutMS=ms: 驅動添加 {wtimeout: ms}getLastError 命令,應用於 safe=true
  • fsync=true|false: 驅動添加 {fsync: true}getLastError 命令,應用於 safe=true
  • journal=true|false: 如果設置為 true,同步到日誌(在提交到資料庫前寫入到實體中),應用於 safe=true
  • connectTimeoutMS=ms: 可以打開連接的時間
  • socketTimeoutMS=ms: 發送和接受 socket 的時間

連接命令格式

使用 mongosh 連接 MongoDB 時,也支持命令選項的方式添加配置:

  • --host arg: 指定資料庫地址
  • --port arg: 指定資料庫埠
  • -u [ --username ] arg: 鑒權的賬號
  • -p [ --password ] arg: 鑒權的密碼

插入文檔

插入校驗

MongoDB 會對要插入的數據進行最基本的檢查:檢查文檔的基本結構,如缺少 _id 鍵會自動添加一個、是否包含非 UTF-8 字元、是否使用了無法識別的類型、檢查文檔大小等。

其中,檢查文檔大小主要因為 MongoDB 限制了所有文檔必須小於 16MB,主要是為了防止不良的模式設計並確保性能上的一致。

要查看文檔的 BSON 大小,可以在 shell 中執行 Object.bsonsize(doc) 查看位元組大小。

單個插入

官方文檔:db.collection.insertOne() — MongoDB Manual

db.collection.insertOne(
    <document>,
    {
        writeConcern: <document>
    }
)

批量插入

官方文檔:db.collection.insertMany() — MongoDB Manual

db.collection.insertMany(
    [ <document 1> , <document 2>, ... ],
    {
        writeConcern: <document>,
        ordered: <boolean>
     }
)

通過傳輸 ordered=true 可以確保文檔按提供的順序插入,指定為 false 則允許 MongoDB 重新排列插入的順序以提高性能,預設為 true 值。

以有序插入的方式使用 insertMany 出現錯誤將會阻塞後續的插入動作,無需插入的方式則不管其他插入是否出現了錯誤。

刪除文檔

單個刪除

官方文檔:db.collection.deleteOne() — MongoDB Manual

db.collection.deleteOne(
    <filter>,
    {
         writeConcern: <document>,
         collation: <document>,
         hint: <document|string>    // Available starting in MongoDB 4.4
    }
)

使用 hint 參數可以指定 filter 查詢時命中的索引,這對於複雜的索引結構時可以提升部分效率。

批量刪除

官方文檔:db.collection.deleteMany() — MongoDB Manual

db.collection.deleteMany(
    <filter>,
    {
         writeConcern: <document>,
         collation: <document>,
         hint: <document|string>    // Available starting in MongoDB 4.4
    }
)

單個刪除並返回

官方文檔:db.collection.findOneAndDelete() — MongoDB Manual

db.collection.findOneAndDelete(
    <filter>,
    {
        writeConcern: <document>,
        projection: <document>,
        sort: <document>,
        maxTimeMS: <number>,
        collation: <document>
    }
)

更新文檔

更新文檔是原子操作:如果兩個更新同時發生,那麼首先到達伺服器的更新會先被執行,然後再執行下一個更新。

因此,相互衝突的更新可以安全地迅速接連完成,而不會破壞任何文檔:最後一次更新將“成功”。如果不想使用預設行為,則可以考慮使用文檔版本控制模式。

單個更新

官方文檔:db.collection.updateOne() — MongoDB Manual

db.collection.updateOne(
    <filter>,
    <update>,
    {
        upsert: <boolean>,
        writeConcern: <document>,
        collation: <document>,
        arrayFilters: [ <filterdocument1>, ... ],
        hint:  <document|string>    // Available starting in MongoDB 4.2.1
    }
)

在更新文檔的時候,比較需要註意的事 upsert 的使用,其是一種特殊類型的更新:如果找不到與篩選條件相匹配的文檔,則會以這個條件和更新文檔為基礎來創建一個新文檔;如果找到了匹配的文檔,則進行正常的更新。

因此,使用 upsert 的好處就是,可以使用同一套代碼創建和更新文檔。

使用 upsert 時就涉及到一個 $setOnInsert 運算符,它的作用是,只會在插入文檔時設置欄位的值,在後續的更新時不對其進行更改。

批量更新

官方文檔:db.collection.updateMany() — MongoDB Manual

db.collection.updateMany(
    <filter>,
    <update>,
    {
        upsert: <boolean>,
        writeConcern: <document>,
        collation: <document>,
        arrayFilters: [ <filterdocument1>, ... ],
        hint:  <document|string>    // Available starting in MongoDB 4.2.1
    }
)

單個替換

官方文檔:db.collection.replaceOne() — MongoDB Manual

db.collection.replaceOne(
    <filter>,
    <replacement>,
    {
        upsert: <boolean>,
        writeConcern: <document>,
        collation: <document>,
        hint: <document|string>     // Available starting in 4.2.1
    }
)

replaceOneupdateOne 操作的區別在於,updateOne 可以更新文檔中部分鍵的值,而 replaceOne 的作用是直接將整個文檔都替換掉,通常是建議使用 updateOne 而不是 replaceOne

單個更新並返回

官方文檔:db.collection.findOneAndUpdate() — MongoDB Manual

db.collection.findOneAndUpdate(
    <filter>,
    <update document or aggregation pipeline>,  // Changed in MongoDB 4.2
    {
        projection: <document>,
        sort: <document>,
        maxTimeMS: <number>,
        upsert: <boolean>,
        returnDocument: <string>,
        returnNewDocument: <boolean>,
        collation: <document>,
        arrayFilters: [ <filterdocument1>, ... ]
    }
)

使用 findOneAndUpdate 而不是 updateOne 的最大目的莫過於使用 findOneAndUpdate 可以返回更新前後文檔內容。

通過設置 returnNewDocument 的值為 true 可以返回更新後的文檔,為 false 時可以返回更新前的文檔。

單個替換並返回

官方文檔:db.collection.findOneAndReplace() — MongoDB Manual

db.collection.findOneAndReplace(
    <filter>,
    <replacement>,
    {
        projection: <document>,
        sort: <document>,
        maxTimeMS: <number>,
        upsert: <boolean>,
        returnDocument: <string>,
        returnNewDocument: <boolean>,
        collation: <document>
    }
)

更新運算符

官方文檔:Update Operators — MongoDB Manual

對於如 updateOneupdateManyfindOneAndUpdate 等更新操作,MongoDB 提供了原子的更新運算符支持只更新部分數據。

運算符支持以 { <operator>: { <field>: <value>,... } } 的方式使用,並且可以同時使用多個運算符。

為避免出現歧義,不建議對同一個屬性同時使用不同的運算符。

欄位

  • $currentDate: 將指定鍵設置為當前時間
  • $inc: 對數字類型的鍵做遞增操作
  • $min: 會比較原始值和更新值,並設置成較小值
  • $max: 會比較原始值和更新值,並設置成較大值
  • $mul: 對數字類型的鍵做乘法操作
  • $rename: 修改指定鍵的名稱
  • $set: 將指定鍵設置為指定值
  • $setOnInsert: 與 upsert 配合使用,如果更新導致文檔插入,則設置欄位的值,對修改現有文檔的更新操作無效
  • $unset: 刪除指定鍵

數組

  • $: 充當占位符,更新與查詢條件匹配的第一個元素
  • $[]: 充當占位符,為匹配查詢條件的文檔更新數組中的所有元素
  • $[<identifier>]: 充當占位符,為匹配查詢條件的文檔更新與 arrayFilters 條件匹配的所有元素
  • $addToSet: 僅當集合中不存在該元素時,才將元素添加到數組中
  • $pop: 傳 { $pop: { field: 1 } } 表示刪除數組中的最後一項,傳 -1 時表示刪除第一項
  • $pull: 刪除與指定查詢匹配的所有數組元素
  • $push: 新增一項到數組中
  • $pullAll: 刪除列出的所有數組元素

數組內層

  • $each: 使用 $push$addToSet 運算符時,增加此運算符可以批量添加元素
  • $position: 與 $each 配合使用,可以指定添加元素的位置
  • $slice: 與 $each 配合使用,防止數組的增長超過某個大小,傳正數表示從左到右截斷
  • $sort: 與 $each 配合使用,對添加完元素的數組進行排序

位運算

$bit: 支持對整數值進行按位 ANDORXOR 更新,通過使用 { $bit: { <field>: { <and|or|xor>: <int> } } } 完成更新。

批量寫操作

官方文檔:db.collection.bulkWrite() — MongoDB Manual

MongoDB 提供了 bulkwrite 命令支持批量執行命令,批處理時在一定程度上減少了網路交互的損耗。

db.collection.bulkWrite(
    [ <operation 1>, <operation 2>, ... ],
    {
         writeConcern: <document>,
         ordered: <boolean>
    }
)

支持的以下操作:

  • insertOne
  • updateOne
  • updateMany
  • replaceOne
  • deleteOne
  • deleteMany

查詢文檔

單個查詢

官方文檔:db.collection.findOne() — MongoDB Manual

db.collection.findOne(query, projection, options)

第一個參數是查詢條件,可以使用鍵值對的方式指定需要匹配的條件,多個鍵之間是 AND 的關係。

第二個參數用於僅返回指定的鍵,既可以節省網路傳輸的數據量,也可以減少客戶端解碼文檔的時間和記憶體消耗。

第三個參數可以指定查詢到可選項,這些選項會修改查詢行為和返回結果的方式。更多查看 官方文檔

批量查詢

官方文檔:db.collection.find() — MongoDB Manual

db.collection.find(query, projection, options)

資料庫會使用游標返回 find 的執行結果。

對於游標,客戶端可以限制結果的數量,跳過一些結果,按任意方向的任意鍵組合對結果進行排序等操作。更多查詢 官方文檔

下述是一些常用的游標方法:

  • count(): 統計游標引用的文檔數量
  • hasNext(): 查詢是否有下一個結果
  • hint(index): 指定游標命中的索引
  • limit(number): 限制返回結果的數量
  • next(): 返回下一個搜索結果
  • size(): 返回應用 skip()limit() 之後的查詢數量
  • skip(number): 控制跳過一定的數量,跳過大量數據會比較慢
  • sort(sort): 使用鍵值對的方式對搜索結果進行排序

在伺服器端,游標會占用記憶體的資源。通常在以下情況會終止游標及進行隨後的清理:

  • 當游標遍歷完成匹配的結果時,它會清除自身
  • 當游標超出客戶端的作用域時,驅動程式會向資料庫發送終止游標的信號
  • 當游標達到 10 分鐘沒有使用時,資料庫游標會被自動銷毀

查詢運算符

官方文檔:Query and Projection Operators — MongoDB Manual

同樣的,設置查詢條件時,MongoDB 提供了查詢運算符支持更多的查詢方式。

比較運算符

  • $eq: 返回等於指定值的結果,等同 { <field>: <value> } 的顯式表示
  • $gt: 返回大於指定值的結果
  • $gte: 返回大於等於指定值的結果
  • $in: 返回等於指定數組中任意一個值的結果,對於一個鍵匹配多個值,$in$or 更方便
  • $lt: 返回小於指定值的結果
  • $lte: 返回小於等於指定值的結果
  • $ne: 返回不等於指定值的結果
  • $nin: 返回不等於指定數組中任意一個值的結果

邏輯運算符

  • $and: 返回同時符合查詢子句要求的結果
  • $not: 元運算符,匹配不符合查詢語句要求的結果
  • $nor: 返回不能同時符合查詢子句要求的結果
  • $or: 返回與任意一個查詢子句的條件匹配的結果

對於普通的 $and 類型查詢,我們總是希望儘可能用最少的參數來限定結果的範圍。而 $or 類型查詢則相反,如果第一個參數能夠匹配儘可能多的文檔,則其效率最高。

元素運算符

  • $exists: 判斷指定鍵是否存在,返回符合要求的結果
  • $type: 判斷指定鍵的數據類型,返回符合要求的結果(好的模式設計不應該出現不同類型)

表達式運算符

  • $expr: 允許使用聚合表達式,適合用在一些比較複雜的查詢語句
  • $jsonSchema: 根據給定的 JSON 模式驗證文檔,返回符合要求的結果
  • $mod: 指定鍵的值執行模運算,返回符合要求的結果
  • $regex: 使用正則表達式對指定鍵做匹配,MongoDB 可以利用索引來查詢首碼正則表達式,但不能用於不區分大小寫的搜索
  • $text: 對使用文本索引的欄位內容執行文本搜索,可以作為一個簡易的搜索引擎使用
  • $where: 允許在查詢時執行任意 JavaScript 代碼(性能較差,儘可能使用 $expr 代替)

數組運算符

  • $all: 匹配包含查詢中指定的所有元素的數組
  • $elemMatch: 用於強制將查詢子句與單個數組元素進行匹配
  • $size: 匹配指定數組長度大小的結果

投影運算符

投影運算符針對的是查詢語句的第二個參數,即返回的結果。

  • $: 僅返回數組中與查詢條件匹配的第一個元素
  • $elemMatch: 對返回結果中的數組元素做 $elemMatch 匹配,僅返回數組中滿足要求的元素
  • $meta: 與 $text 運算符配合使用,返回與文檔關聯的元數據,可以返回匹配分數,或者索引鍵
  • $slice: 對返回結果中的數組做截取返回

特殊的 null 值

在 MongoDB 中,null 是一個比較特殊的值,它可以與自身匹配。也就是說了,通過 { field: null } 可以查詢出 field 鍵為 null 的文檔。

不過,更特殊的是,null 同樣會匹配缺少這個鍵值的文檔。也就是說,{ field: null } 可以查詢出不包含 field 鍵的文檔。

如果僅想匹配鍵值為 null 的文檔,則需要檢查該鍵的值是否為 null,並且通過 $exists 條件確認該鍵已存在,如 { field: { $eq: null, $exists: true } } 就是這樣的查詢條件組。

首發於翔仔的個人博客,點擊查看更多。


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

-Advertisement-
Play Games
更多相關文章
  • 前言 拋開死鎖不談,只聊性能問題,儘管鎖總能粗暴的滿足同步需求,但一旦存在競爭關係,意味著一定會有線程被阻塞,競爭越激烈,被阻塞的線程越多,上下文切換次數越多,調度成本越大,顯然在高併發的場景下會損害性能。在高併發高性能且要求線程安全的述求下,無鎖構造(非阻塞構造)閃亮登場。 參考文檔: C# - ...
  • 在 Windows 環境下如果採用 IIS 作為 網站伺服器時,常規的網站綁定 HTTPS 需要一個一個站點手動選擇對應的證書綁定,而且證書過期之後更換證書時也是需要一個個重新綁定操作,無法便捷的做到像 Nginx 或者 Apache 等程式一樣,直接在配置文件中指定所需要使用的證書文件的路徑,像 ...
  • //源文件 void RccPhyConfig() { uint16_t retry = 0; RCC->APB1ENR|=1<<28; //電源介面時鐘使能 PWR->CR1|=3<<14; //高性能模式,時鐘可到 180Mhz PWR->CR1|=1<<16; //使能過驅動,頻率可到 216 ...
  • Babelfish是在PostgreSQL的基礎之上實現了類似Microsoft SQL Server部分功能。為了實現這個目標,PostgreSQL核心內部的幾個部分必須被修改。PostgreSQL 沒有提供這種開箱即用的功能,因此必須提供附加組件才能實現這一點。 Babelfish... ...
  • 摘要:數據加密作為有效防止未授權訪問和防護數據泄露的技術,在各種信息系統中廣泛使用。作為信息系統的核心,GaussDB(DWS)數倉也提供數據加密功能,包括透明加密和使用SQL函數加密。 本文分享自華為雲社區《看GaussDB(DWS)如何使用SQL加密函數實現數據列加解密》,作者:Hello EI ...
  • 近年來,憑藉高可擴展、高可用等技術特性,分散式資料庫正在成為金融行業數字化轉型的重要支撐。分散式資料庫如何在不同的金融級應用場景下,在確保數據一致性的前提下,同時保障系統的高性能和高可擴展性,是分散式資料庫的一個核心技術挑戰。 針對以上分散式一致性的困境,中國人民大學-騰訊協同創新實驗室研究提出“多 ...
  • ​摘要:賬本資料庫融合了區塊鏈思想,將用戶操作記錄至兩種歷史表中:用戶歷史表和全局區塊表。 本文分享自華為雲社區《openGauss賬本資料庫,你不知道的那些事兒》,作者:Gauss松鼠會。 賬本資料庫融合了區塊鏈思想,將用戶操作記錄至兩種歷史表中:用戶歷史表和全局區塊表。當用戶創建防篡改用戶表時, ...
  • 引子 在使用events_statements_current的過程中發現,同一線程在同一時刻,可能有多條記錄,與直觀感覺不太一樣,於是跟蹤了一下內部實現,有了本文。 STATEMENT STACK的定義 STATEMENT STACK 是events_statements_current表被後用於 ...
一周排行
    -Advertisement-
    Play Games
  • 下麵是一個標準的IDistributedCache用例: public class SomeService(IDistributedCache cache) { public async Task<SomeInformation> GetSomeInformationAsync (string na ...
  • 這個庫提供了在啟動期間實例化已註冊的單例,而不是在首次使用它時實例化。 單例通常在首次使用時創建,這可能會導致響應傳入請求的延遲高於平時。在註冊時創建實例有助於防止第一次Request請求的SLA 以往我們要在註冊的時候實例單例可能會這樣寫: //註冊: services.AddSingleton< ...
  • 最近公司的很多項目都要改單點登錄了,不過大部分都還沒敲定,目前立刻要做的就只有一個比較老的項目 先改一個試試手,主要目標就是最短最快實現功能 首先因為要保留原登錄方式,所以頁面上的改動就是在原來登錄頁面下加一個SSO登錄入口 用超鏈接寫的入口,頁面改造後如下圖: 其中超鏈接的 href="Staff ...
  • Like運算符很好用,特別是它所提供的其中*、?這兩種通配符,在Windows文件系統和各類項目中運用非常廣泛。 但Like運算符僅在VB中支持,在C#中,如何實現呢? 以下是關於LikeString的四種實現方式,其中第四種為Regex正則表達式實現,且在.NET Standard 2.0及以上平... ...
  • 一:背景 1. 講故事 前些天有位朋友找到我,說他們的程式記憶體會偶發性暴漲,自己分析了下是非托管記憶體問題,讓我幫忙看下怎麼回事?哈哈,看到這個dump我還是非常有興趣的,居然還有這種游戲幣自助機類型的程式,下次去大玩家看看他們出幣的機器後端是不是C#寫的?由於dump是linux上的程式,剛好win ...
  • 前言 大家好,我是老馬。很高興遇到你。 我們為 java 開發者實現了 java 版本的 nginx https://github.com/houbb/nginx4j 如果你想知道 servlet 如何處理的,可以參考我的另一個項目: 手寫從零實現簡易版 tomcat minicat 手寫 ngin ...
  • 上一次的介紹,主要圍繞如何統一去捕獲異常,以及為每一種異常添加自己的Mapper實現,並且我們知道,當在ExceptionMapper中返回非200的Response,不支持application/json的響應類型,而是寫死的text/plain類型。 Filter為二方包異常手動捕獲 參考:ht ...
  • 大家好,我是R哥。 今天分享一個爽飛了的面試輔導 case: 這個杭州兄弟空窗期 1 個月+,面試了 6 家公司 0 Offer,不知道問題出在哪,難道是杭州的 IT 崩盤了麽? 報名面試輔導後,經過一個多月的輔導打磨,現在成功入職某上市公司,漲薪 30%+,955 工作制,不咋加班,還不捲。 其他 ...
  • 引入依賴 <!--Freemarker wls--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency> ...
  • 你應如何運行程式 互動式命令模式 開始一個互動式會話 一般是在操作系統命令行下輸入python,且不帶任何參數 系統路徑 如果沒有設置系統的PATH環境變數來包括Python的安裝路徑,可能需要機器上Python可執行文件的完整路徑來代替python 運行的位置:代碼位置 不要輸入的內容:提示符和註 ...