欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

MongoDB的一些操作技巧

程序员文章站 2022-07-05 17:11:12
去年三月底入职上海的一家互联网公司,由于项目使用的是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操作!!!!!

吐槽一下:不知道为什么总能遇到一些拥有迷之自信的程序员? 不知道各位同仁有没有遇到过拥有迷之自信的程序员?