這些MongoDB的隱藏操作你真的都掌握了嗎?反正我是剛知道

来源:https://www.cnblogs.com/SwordArt/archive/2020/03/15/12497697.html
-Advertisement-
Play Games

背景 最近公司系統還原用戶時偶爾會出現部分用戶信息未還原成功的問題,最為開發人員,最頭疼的不是代碼存在bug,而是測試發現了bug,但一旦我去重現,它就不見了。Are you kidding me? 經過漫長的溝通與嘗試,終於發現了端倪,這個問題只有在多人同時操作修改同一用戶信息時才會出現。 哦,那 ...


背景

最近公司系統還原用戶時偶爾會出現部分用戶信息未還原成功的問題,作為開發人員,最頭疼的不是代碼存在bug,而是測試發現了bug,但一旦我去重現,它就不見了。Are you kidding me?

經過漫長的溝通與嘗試,終於發現了端倪,這個問題只有在多人同時操作修改同一用戶信息時才會出現。

哦,那你死定了,小bug。

分析

經過短暫的代碼review,發現還原用戶時,代碼中會先把用戶獲取出來,然後修改用戶信息,最後再將修改後的用戶更新至資料庫中。

var user1 = collection.Find(x => x.Id == "user1").FirstOrDefault();
user1.Name = "B";
collection.ReplaceOneAsync(x => x.Id == "user1", user1);

這就導致代碼併發運行時,後面的可能覆蓋前方的操作。

如下圖操作1及操作2執行結束後,資料庫中用戶1的名稱為A,年齡為18;操作1的修改用戶名稱為B被覆蓋.

 

所以我們需要採用原子操作來修改用戶信息,我們調整代碼如下

UpdateDefinition<Persion> update = Builders<Persion>.Update.Set(y => y.Name, "B");
collection.UpdateOne(x => x.Id == "user1", update);

這樣就把修改操作交給資料庫來執行,僅修改要修改的屬性,避免操作互相影響;

看到這裡有的大神就會吐槽,這麼簡單的東西也好意思拿來說,請在耐心往下看,重點在下邊。

重點

如果我們的數據結構類似這樣:

/// <summary>
////// </summary>
[BsonIgnoreExtraElements]
public class Persion : BaseEntity
{
    /// <summary>
    /// 名稱
    /// </summary>
    [BsonElement("name")]
    public string Name { get; set; }

    /// <summary>
    /// 年齡
    /// </summary>
    [BsonElement("age")]
    public int Age { get; set; }

    /// <summary>
    /// 親戚
    /// </summary>
    [BsonElement("relatives")]
    public List<Relative> Relatives { get; set; }

}
/// <summary>
/// 親屬
/// </summary>
public class Relative
{
    /// <summary>
    /// 名稱
    /// </summary>
    [BsonElement("name")]
    public string Name { get; set; }

    /// <summary>
    /// 與本人關係
    /// </summary>
    [BsonElement("relationship")]
    public Relationship Relationship { get; set; }
}
/// <summary>
/// 與本人關係
/// </summary>
public enum Relationship
{
    /// <summary>
    /// 爸爸
    /// </summary>
    father = 0,
    /// <summary>
    /// 媽媽
    /// </summary>
    mother = 1,
    /// <summary>
    /// 兒子
    /// </summary>
    son = 2,
    /// <summary>
    /// 女兒
    /// </summary>
    daughter = 3,
    /// <summary>
    /// 不明
    /// </summary>
    unknow = 100
}

如果我們想更新名稱為“趙小明”的人的名稱為“趙剛”的親戚與本人關係為“爸爸”,請考慮,應該怎麼處理。

註意:人的親戚可以有多個,所以是List。

這時我們就用到了ArrayFilters對象,其存在於UpdateOptions中,如果沒有系統的看過MongoDB的介面,我相信大部分人都會忽略它。

好了,廢話不多說,讓我們來看看它的用法吧

FilterDefinition<Persion> filter = Builders<Persion>.Filter.Where(x => x.Name == "趙小明" && x.Relatives != null && x.Relatives.Count > 0);

UpdateDefinition<Persion> update = Builders<Persion>.Update.Set("relatives.$[i].relationship", Relationship.father);

var option = new UpdateOptions()
{
    ArrayFilters = new List<ArrayFilterDefinition> {
        new JsonArrayFilterDefinition<Relationship>("{'i.name': '趙剛'}")
    }
};

collection.UpdateMany(filter, update, option);

可以看到,我們先生成一個查詢條件,名稱為“趙小明”,存在親戚的人;

然後更新其"relatives.$[i].relationship"屬性,為Relationship.father,其中的$[i]為占位符;

再生成一個決定$[i]值的JsonArrayFilterDefinition<Relationship>("{'i.name': '趙剛'}")

最後用這些條件來更新資料庫。

引申

好了,更新是實現了,那有求知欲的小伙伴就會想查詢怎麼辦呢?

這還不簡單,一行語句就搞定了

var user = collection.Find(x => x.Name == "趙小明" && x.Relatives != null && x.Relatives.Count > 0 && x.Relatives.Exists(y => y.Name == "趙剛")).FirstOrDefault();

沒錯,但如果此人存在幾千萬個親戚(現實生活中怎麼可能,笑),我只需要其與一個名為“趙剛”的親戚的關係,不想把整個對象都載入到記憶體中怎麼辦?

這時我們就需要用到ProjectionDefinitionBuilder對象了,

FilterDefinition<Persion> filter = Builders<Persion>.Filter.Where(x => x.Name == "趙小明" && x.Relatives != null && x.Relatives.Count > 0);

var findOptions = new FindOptions<Persion, Relative>()
{
    Projection = new ProjectionDefinitionBuilder<Persion>().Expression(x => x.Relatives.FirstOrDefault(r => r.Name != "趙剛"))
};

Relative cursor = collection.FindSync(filter, findOptions).FirstOrDefault();

我們就得到了我們想要的親戚對象,而不是包含幾千萬親戚信息的完整Persion對象了。

結語

作為一名博客萌新,我只是將我遇到的問題總結下來並分享給大家,有不對的地方,務必幫忙指正。

當然上面的內容對於大佬來說可能是常規操作,但如果對你有一點點用處,請點贊,評論,並關註下。

後面我會將我在工作學習中遇到的有趣的問題分享給大家,謝謝!!!


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

-Advertisement-
Play Games
更多相關文章
  • 我們可以在Github上面直接查看ASP.NET Core 3.x的源代碼,但是我們也可以把源代碼下載下來進行查看。 而下載源代碼進行查看有很多好處: 任意的導航源代碼 內置了一個示例項目 直接調試源代碼 下載源代碼 想下載並配置好源碼,你需要: 最新版的Visual Studio 或者其它IDE ...
  • 前言 Identity Server4基於OAuth2.0協議的一套用於身份認證和授權的框架。OAuth2.0協議是一個委托協議,通過這個協議,我們可以讓某個客戶端頂著一個有資源訪問許可權的身份去訪問那些被保護的資源。授權的流程簡單概括起來,客戶端應用需要先去請求Identity Server4,如果 ...
  • 前要: 有一12年買的手提電腦,打算在其上直接裝linux部署分散式爬蟲順便學linux 唔,開機吧……然開機動畫沒有,只有間斷有序的悲鳴,一查,主板逝世 賣給收買舊電腦估計不到20…不能忍,想了想不如裝移動硬碟上做個mobile linux,OK,遂寫此篇 工具: 硬碟盒/移動硬碟、U盤、(環境w ...
  • Ansible的指定用戶與密碼登錄、免密登錄、指定ssh埠以及主機清單Inventory配置 ...
  • [linux內核分析———SLAB原理及實現 ](https://blog.csdn.net/chenxiancool/article/details/7638804) Slab原理及實現 1. 整體關係圖 ! 註:SLAB,SLOB,SLUB都是內核提供的分配器,其前端介面都是一致的,其中SLAB ...
  • 最近使用brew update時,發現homebrew更新緩慢;於是進行更換為國內源; 晚上這種教程很多,我選擇的是中科大的源;當然清華的源也是可以的,這取決於你當前所處的地理位置,這樣有更通暢的網路鏈接; https://mirrors.ustc.edu.cn/help/brew.git.html ...
  • turtle庫的學習筆記(python) turtle(海龜)是Python重要的標準庫之一,它能夠進行基本的圖形繪製。turtle圖形繪製的概念誕生於1969年,成功應用於LOGO編程語言。turtle庫繪製圖形有一個基本框架:一個小海龜在坐標系中爬行,其爬行軌跡形成了繪製圖形。剛開始繪製時,小海 ...
  • 原文鏈接: "https://xiaoheidiannao.com/articles/Vim For Chrome.html" "Chrome瀏覽器" 有很多強大的擴展程式,其中我最喜歡的就是Vimium,其他的擴展程式都可以不安裝,但就是這個一定要安裝,用過以後你就會發現你已經離不開它了! Vim ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...