去年三月底入職上海的一家互聯網公司,由於項目使用的是MongoDB資料庫所以有機會接觸了MongoDB。在項目的開發過程中使用系統原有的一些方法查詢MongoDB感覺很費力,用起來也不爽,所以私下裡就自己學了一些C#查詢MongoDB的方法。 先說一些MongoDB的內嵌數組查詢,公司原有的方法是使 ...
去年三月底入職上海的一家互聯網公司,由於項目使用的是MongoDB資料庫所以有機會接觸了MongoDB。在項目的開發過程中使用系統原有的一些方法查詢MongoDB感覺很費力,用起來也不爽,所以私下裡就自己學了一些C#查詢MongoDB的方法。
先說一些MongoDB的內嵌數組查詢,公司原有的方法是使用Map進行聚合,這導致查詢效率底下。多個項目組的成員都有抱怨。
在研究MongoDB測試用例後總結出使用投影技術來替換Map的方法:
public class Test { public ObjectId Id{get;set;} public string AAA{get;set;} public IList<TestOne> TestOneList{get;set;} } public class TestOne
{ public long TestOneId{get;set;}
public string Name{get;set;}
public IList<TestTwo> TestTwoList{get;set;} }
public class TestTwo
{
public long TestTwoId{get;set;}
}
假定有這麼一個數據結構 我想查詢指定的TestOne 我們就可以利用投影技術來實現
var projection = new ProjectionDefinitionBuilder<Test>();
var pp = projection.Expression(r =>
r.TestOneList.FirstOrDefault(s => s.TestOneId == 123));
dbContext.Get(filter, new FindOptions<Test, TestOne>()
{
Projection = pp
});
這樣我們就可以直接拿到指定的TestOne 了。同樣對於多層嵌套 我們可以在Expression里一層一層往下寫
var pp = projection.Expression(r => r.TestOneList.FirstOrDefault(s => s.TestOneId == 123).TestTwoList.FirstOrDefault(t=>t.TestTwoId==333));dbContext.Get(filter, new FindOptions<Test, TestTwo>() { Projection = pp });
在公司的測試伺服器上相較map方式性能提升近10倍 。
在MongoDB中我們常常會面臨一個問題,一個文檔的數據量過大,譬如 我們TestTwoList里的數據量達到萬級別,這個時候我們查詢一個Test數據的耗時肯定會非常的大,即便是我們放到Redis等緩存中依然會很慢。那麼有什麼方法能夠優化呢?
在實際使用過程中我們的各個業務不同對於Test里的數據需要也不同,比如業務A只需要Test中的TestOne 的Name信息,業務B只需要Test中的AAA信息。那麼我們可以根據實際需要來進行投影以獲取我們實際需要的數據,而不是獲取所有的數據。
var rr = Builders<Test>.Filter.Eq(r=>r.Id, 1123123); var project =new ProjectionDefinitionBuilder<Test>(); var pp = project.Include("Name"); var ss = dbContext.Get(rr, new FindOptions<Test, 自定義類型>() { Projection = pp });
這樣我們就可以只拿我們需要的數據。
Linq 查詢MongoDB。我們拿到Query後可以使用Linq進行各種查詢,group 等。非常實用。
最後呢推薦一種 多層嵌套數據操作方法,在多層數組嵌套中最難搞得就是定位的問題。好在MongoDB官方在3.6版本提供了ArrayFilters ,極大的方便了開發人員
var filterBuiler = Builders<Test>.Filter; var filter = filterBuiler.Eq(r => r.Id, 598882505); var ArrayFilters = new List<ArrayFilterDefinition>(); ArrayFilters.Add(new JsonArrayFilterDefinition<Test>("{\"i.TestOneId\":{$eq:"+ 598882571 + "}}")); ArrayFilters.Add(new JsonArrayFilterDefinition<Test>("{\"j.TestTwoId\":{$eq:" + 598882573 + "}}")); UpdateOptions updateOptions=new UpdateOptions(); updateOptions.ArrayFilters = ArrayFilters; var update = new UpdateDefinitionBuilder<Test>(); var updatef = update.Set("TestOneList.$[i].TestTwoList.$[j].xxxxx", "哈哈"); await dbContext.UpdateAsync(filter, updatef, updateOptions);
這種方法只被3.6版本的資料庫支持
使用MongoDB的同仁一定要記得 MongoDB中對於整數,長整數,雙精度浮點數有一個Inc操作!!!!!
吐槽一下:不知道為什麼總能遇到一些擁有迷之自信的程式員? 不知道各位同仁有沒有遇到過擁有迷之自信的程式員?