C# 读写MongoDB

驱动:Official .NET driver for MongoDB

版本:2.5.0

 mongodb内部是用Bson格式存储的,与json大致类似但有区别,因此它也原生支持json串语法格式进行操作,

在C#版本驱动中就有BsonDucument类来处理json串,

所以大多驱动接口的泛型参数TDocument类型都可以用BsonDucument,即直接用BsonDucument来处理json和bson进行增删改查。

但是我不喜欢在C#语言还去写json,总觉得这样做以后比较难维护,所以尽量用C#语法本身去操作。

得益于驱动提供了BsonSerializer类,能够将C#中的大多数自定义class对象进行序列化与反序列化。

所以TDocument泛型参数不受限于BsonDucument,可以是任何自定义的类对象,

它内部可以将自定义的类对象序列化成BsonDucument,也可以反序列化,于是就可以在自定义对象层面操作mongodb了。

先简单做个封装类:

using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using MongoDB.Bson.Serialization.Attributes;

public class MongoDbHelper
    {
        private readonly IMongoDatabase _database;

        private MongoDbHelper(string connectionString, string databaseName)
        {
            var client = new MongoClient(connectionString);
            _database = client.GetDatabase(databaseName);
        }

        public Task Close()
        {
            return Task.CompletedTask;
        }

        public async Task EnsureIndexes<TC,TD>(IEnumerable<string> keys)
        {
            var collection = _database.GetCollection<TD>(typeof(TC).Name);
            await collection.Indexes.CreateManyAsync(keys.Select(key => new CreateIndexModel<TD>($"{{{key}:1}}")));
        }

        public Task<long> CountAsync<T>(string grainType, Expression<Func<T, bool>> whereFilter)
        {
            var collection = _database.GetCollection<T>(grainType);
            return collection.CountAsync(whereFilter == null ? FilterDefinition<T>.Empty :
                Builders<T>.Filter.Where(whereFilter));
        }

        
        public Task WriteData<T>(string collectionName, IEnumerable<T> data)
        {
            var collection = _database.GetCollection<BsonDocument>(collectionName);
            collection.InsertManyAsync(data.Select(d => d.ToBsonDocument())); //对象可以直接转Bson
            return Task.CompletedTask;
        }

        //TC用来指明数据库的Collection名,相当于sql表名;
        //TD类型用来指明文档序列化对象,相当于sql记录所对应的对象
        public Task WriteData<TC,TD>(IEnumerable<TD> data)
        {
             return WriteData<TD>(typeof(TC).Name, data);
        }

        //T类型用来指明文档序列化对象,相当于sql记录所对应的对象
        public async Task<List<T>> Query<T>(string collectionName, Expression<Func<T, bool>> whereFilter)
        {
            try
            {
                var collection = _database.GetCollection<T>(collectionName);
                var filterDefinition = whereFilter == null
                    ? FilterDefinition<T>.Empty
                    : Builders<T>.Filter.Where(whereFilter);
                var projection = Builders<T>.Projection.Exclude("_id");
                var findoptions = new FindOptions<T>() { Projection = projection };
                var cursor = await collection.FindAsync(filterDefinition, findoptions);
                return cursor.ToEnumerable().ToList();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            return null;
        }

        public Task<List<TD>> Query<TC, TD>(Expression<Func<TD, bool>> whereFilter)
        {
            return Query(typeof(TC).Name, whereFilter);
        }

        private async Task<List<TO>> AggregateQuery<TI, TO>(string collectionName, IEnumerable<IPipelineStageDefinition> pipelineStage)
        {
            try
            {
                var pipeline = new PipelineStagePipelineDefinition<TI, TO>(pipelineStage);
                var collection = _database.GetCollection<TI>(collectionName);
                var result = await collection.AggregateAsync(pipeline);
                return result.ToEnumerable().ToList();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            return null;
        }

        public Task<List<TO>> AggregateQuery<TC, TI, TO>(IEnumerable<IPipelineStageDefinition> pipelineStage)
        {
            return AggregateQuery<TI,TO>(typeof(TC).Name, pipelineStage);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TC">collection名称类</typeparam>
        /// <typeparam name="TI">输入文档类</typeparam>
        /// <typeparam name="TG">group by字段类型</typeparam>
        /// <typeparam name="TO">输出类型</typeparam>
        /// <param name="match"></param>
        /// <param name="groupby"></param>
        /// <param name="groupValue"></param>
        /// <returns></returns>
        public async Task<List<TO>> AggregateQuery<TC,TI,TG,TO>(Expression<Func<TI, bool>> match,
            Expression<Func<TI, TG>> groupby,
            Expression<Func<IGrouping<TG, TI>, TO>> groupValue)
        {
            var pipelineStageDefinitions = new IPipelineStageDefinition[]
            {
                PipelineStageDefinitionBuilder.Match(match),
                PipelineStageDefinitionBuilder.Group(
                    groupby,
                    groupValue)
            };
            return await AggregateQuery<TC, TI, TO>(pipelineStageDefinitions);
        }

        private async Task<List<T>> AggregateQuery<T>(string collectionName, IEnumerable<IPipelineStageDefinition> pipelineStage)
        {
            try
            {
                var pipeline = new PipelineStagePipelineDefinition<BsonDocument, BsonDocument>(pipelineStage);
                var collection = _database.GetCollection<BsonDocument>(collectionName);
                var result = await collection.AggregateAsync(pipeline);
                return result.ToEnumerable().Select(b => BsonSerializer.Deserialize<T>(b)).ToList();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            return null;
        }

        public Task<List<TO>> AggregateQuery<TC,TO>(IEnumerable<string> pipelineStageJson)
        {
            return AggregateQuery<TO> (typeof(TC).Name,pipelineStageJson.Select(
                json => new JsonPipelineStageDefinition<BsonDocument,BsonDocument>(json)
                    as IPipelineStageDefinition).ToList());
        }
    }

 

自定义一个类:

 

 

public class Recharge
    {
        public long UserId { get; set; }
        public ulong Amount { get; set; }
        [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
        public DateTime Time { get; set; } = DateTime.Now;
    }


先打开个数据库连接:

 

//连接串和数据库名参数按自己的实际情况填
     var helper = new MongoDbHelper("XXXX","YYYY");

 

写数据:

 

        //写入多条数据
            await helper.WriteData<Recharge, Recharge>(new[]
            {
                new Recharge() {UserId = 1, Amount = 100},
                new Recharge() {UserId = 1, Amount = 200},
                new Recharge() {UserId = 2, Amount = 500},
                new Recharge() {UserId = 2, Amount = 1000},
                new Recharge() {UserId = 3, Amount = 800},
                new Recharge() {UserId = 4, Amount = 100},
            });

 

查询数据:

 

       //按id筛选
            var list1 = await helper.Query<Recharge, Recharge>(recharge=>recharge.UserId == 1);
            
            //按时间筛选
            var list2 = await helper.Query<Recharge, Recharge>(
                recharge => recharge.Time >= DateTime.MinValue &&
                            recharge.Time <= DateTime.Now);

            //按金额筛选
            var list3 = await helper.Query<Recharge, Recharge>(
                recharge => recharge.Amount >= 500);

注:开始新手的我以为查询过程是:先将bson文档反序列化成C#对象,再调用C#的lambda进行筛选。如果直接这样,效率肯定很低,相当于总是要全盘扫描。而实际上是驱动内部把lambda函数解析成了Expression表达式,再解析翻译为了原生json串查询语法,相较于原本的json语法操作,只是牺牲了点翻译时间。


统计查询:

 

       //先定义一个统计类对象
            public class RechargeStat
            {
                public long UserId { get; set; }
                public ulong Amount { get; set; }
            }

            //统计所有人的总充值
            var stats = await helper.AggregateQuery<Recharge, Recharge, long, RechargeStat>(
                recharge=>true, //直接返回true,即不筛选
                recharge=>recharge.UserId,//按UserId统计,相当于sql的group by UserId
                group =>new RechargeStat()
                {
                    UserId = group.Key,
                    Amount = (ulong)group.Sum(v=>(double)v.Amount)
                }
            );

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
C#MongoDB的分片是指将MongoDB数据库的数据水平分割为多个分片(shard),以实现数据的分布式存储和处理。C#是一种编程语言,而MongoDB是一种NoSQL数据库。 在C#中,可以使用MongoDB的官方驱动程序来进行与MongoDB数据库的交互和操作。要使用分片功能,首先需要在MongoDB服务器上进行配置和设置。以下是基本的步骤: 1. 安装和配置MongoDB服务器:确保MongoDB服务器已正确安装并启动。在服务器配置文件中启用分片功能。 2. 创建MongoDB分片集群:在服务器上创建一个或多个分片节点,并将它们集成为一个分片集群。 3. 配置MongoDB路由器:配置MongoDB路由器(也称为mongos)以连接到分片集群,并提供客户端访问接口。 4. 创建分片键:选择一个合适的字段作为分片键,并将其用于将数据分布到不同的分片上。分片键的选择对于数据均衡和查询性能至关重要。 5. 启用分片:在MongoDB路由器上使用相应的命令或API启用分片功能,并指定分片键。 一旦完成上述配置,你可以使用C#编写代码来连接到MongoDB路由器,并执行对数据库的操作。在C#中,可以使用MongoDB的官方驱动程序提供的API来进行插入、查询、更新和删除等操作。根据你的具体需求,可以编写适当的代码来处理分片集群中的数据。 需要注意的是,分片功能的配置和使用相对复杂,需要仔细考虑数据模型和查询模式,以确保良好的性能和可扩展性。在开发过程中,可以参考MongoDB官方文档和C#驱动程序的文档来获取更详细的信息和示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值