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;}<br /> public string Name{get;set;}<br /> public IList<TestTwo> TestTwoList{get;set;} }<br /><br />public class TestTwo<br />{<br /> public long TestTwoId{get;set;}<br />}
假定有这么一个数据结构 我想查询指定的TestOne 我们就可以利用投影技术来实现
var projection = new ProjectionDefinitionBuilder<Test>();<br />
var pp = projection.Expression(r =><span> 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, ); 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操作!!!!!
吐槽一下:不知道为什么总能遇到一些拥有迷之自信的程序员? 不知道各位同仁有没有遇到过拥有迷之自信的程序员?