NoSQL是泛指非关系型的数据库,现今在我们的项目中也多有使用,其独特的优点为我们的项目架构带来了不少亮点,而我们这里的主角(MongoDB)则是NoSQL数据库家族中的一种。事实上,NoSQL数据库的应用场景有很多,其最主要的目的就是为了能解决大规模数据集合多重数据种类带来的困难,及大数据应用的难题。
MongoDB
MongoDB是一个开源的文档型数据库,由C++语言编写,采用分布式的文件存储方案,而文件的存储格式为BSON。MongoDB支持的数据类型有很多种,如:String、Int、Float、Timestamp、Binary、Object、Date、Arrays等。而MongoDB的特点也有很多,如:强大的查询语言、支持索引、支持自动处理碎片、支持JAVA/C#/Python等多种开发语言、支持面向集合存储等。关于MongoDB的具体描述也可自行到其官网查看,我这里就不再过多啰嗦了,下面贴出与其几个相关的网址吧:
MongoDB官网:https://www.mongodb.com/
MongoDB官方的.NET API文档:http://api.mongodb.com/csharp/current/html/R_Project_CSharpDriverDocs.htm
MongoDB官方的github网址:https://github.com/mongodb/mongo
MongoDB可视化管理工具NoSQL Manager for MongoDB的官网:https://www.mongodbmanager.com/
背景
在大部分的项目中都会遇到要将短消息类型的数据(比如企业系统内的用户操作行为的“操作日记”数据、聊天通讯系统内的“对话记录”等数据)做持久化,而这种数据的特征就是关系简单、数据量庞大、大部分只有读写操作等。基于这些业务需要与应用场景,那么我们就可以考率使用MongoDB来做数据的持久化存储与管理了。
在这里,我们将模拟一个基于Saas平台下的企业系统内“操作日记”的业务场景(项目将以Saas服务提供给各个企业使用,并将所有用户在系统上的操作行为以日记方式存储到数据库去),并使用MongoDB来做数据的持久化存储与管理(包含对数据的增加与查询操作)。这里我们为了简便则将代码的结构层次分为两层(实际项目中各位按需分层级),那么项目结构将是这个样子的:
1、Lezhima.Web:接受来自客户端的请求,及服务端响应的出入口。由一个基于ASP.NET Core的MVC项目组成。
2、Lezhima.Data:直接跟MongoDB进行通讯交互,实现对DB的增、查等操作。由一个基于.NET Core的类库组成。
业务规则:
基于上述的应用场景所悉,我们将面向的是企业客户,且是以Saas服务运行在云上的,则我们操作管理MongoDB时将面临如下几个规则(基于海量数据的读写考率):
1、希望数据能按企业ID分库,即各个企业的数据归档到其对应的独立库中。
2、能根据日期每天分表存储数据。
3、分库能按企业ID自动完成,分表能按日期自动完成。
与MongoDB通讯的API类库:
我们将使用由MongoDB官方提供的API类库来与MongoDB进行通讯与交互,在Lezhima.Data项目中可通过NuGet管理器引用如下两个类库:
1、MongoDB.Bson
2、MongoDB.Driver
实现代码
通过上面的介绍,我们清楚了两个分层之间的功能与关系,那么接下来我们就分别来看看它们具体的代码,及操作MongoDB的简便酷爽吧。
1、我们先看看Lezhima.Data层的代码,首先定义一个名为“MongoDbContext”类,用于管理MongoDB的上下文,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Security.Authentication; using System.Text.RegularExpressions; using System.Threading.Tasks; using MongoDB.Bson; using MongoDB.Driver; namespace Lezhima.Data.Context { /// <summary> /// MongoDB对象的上下文 /// </summary> public class MongoDbContext { /// <summary> /// Mongo上下文 /// </summary> public IMongoDatabase DbContext { get; } /// <summary> /// 初始化MongoDb数据上下文 /// 将数据库名传递进来 /// </summary> public MongoDbContext(string dbName) { //连接字符串,如:"mongodb://username:password@host:port/[DatabaseName]?ssl=true" //建议放在配置文件中 var connectionString = "mongodb://root:a123@192.168.1.6:27017"; try { var mongoClient = new MongoClient(connectionString); //数据库如果不存在,会自动创建 DbContext = mongoClient.GetDatabase(dbName); } catch (Exception e) { Log.WriteLogByError("构建MongoDbContext出错", e); throw; } } /// <summary> /// 异步获取表(集合) /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="datetime"></param> /// <returns></returns> public async Task<IMongoCollection<TEntity>> GetCollectionAsync<TEntity>(string tableName="") where TEntity : class { var dt = DateTime.Now.ToString("yyyy -MM-dd"); if (!string.IsNullOrEmpty(tableName)) { dt = tableName; } // 获取集合名称,使用的标准是在实体类型名后添加日期 var collectionName = dt; // 如果集合不存在,那么创建集合 if (false == await IsCollectionExistsAsync<TEntity>(collectionName)) { await DbContext.CreateCollectionAsync(collectionName); } return DbContext.GetCollection<TEntity>(collectionName); } /// <summary> /// 集合是否存在 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <returns></returns> public async Task<bool> IsCollectionExistsAsync<TEntity>(string name) { var filter = new BsonDocument("name", name); // 通过集合名称过滤 var collections = await DbContext.ListCollectionsAsync(new ListCollectionsOptions { Filter = filter }); // 检查是否存在 return await collections.AnyAsync(); } } }
2、在Lezhima.Data层增加一个名为“IMongoRepository”接口,用于封装向业务层提供操作MongoDB的操作方法,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; using MongoDB.Bson; using MongoDB.Driver; namespace Lezhima.Data.Interface { public interface IMongoRepository<T> where T : class { /// <summary> /// 从指定的库与表中获取指定条件的数据 /// </summary> /// <returns></returns> Task<List<T>> GetListAsync(Expression<Func<T, bool>> predicate, string dbName, string tableName = ""); /// <summary> /// 对指定的库与表中新增数据 /// </summary> /// <returns></returns> Task<bool> Add(List<T> list, string dbName, string tableName = ""); } }
3、在Lezhima.Data层再增加一个名为“MongoRepository”类,实现“IMongoRepository”接口,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; using System.Web; using Lezhima.Data.Context; using Lezhima.Data.Interface; using MongoDB.Bson; using MongoDB.Driver; namespace Lezhima.Data { /// <summary> /// 封装向业务层提供操作MongoDB的操作方法 /// </summary> /// <typeparam name="T"></typeparam> public class MongoRepository<T> : IMongoRepository<T> where T : class { /// <summary> /// 从指定的库与表中获取指定条件的数据 /// </summary> /// <returns></returns> public async Task<List<T>> GetListAsync(Expression<Func<T, bool>> predicate, string dbName, string tableName) { var dbContext = new MongoDbContext(dbName); var collection = await dbContext.GetCollectionAsync<T>(tableName); return collection.AsQueryable<T>().Where(predicate).ToList(); } /// <summary> /// 对指定的库与表中新增数据 /// </summary> /// <returns></returns> public async Task<bool> Add(List<T> list, string dbName, string tableName = "") { var dbContext = new MongoDbContext(dbName); var collection = await dbContext.GetCollectionAsync<T>(tableName); await collection.InsertManyAsync(list); return true; } } }
4、在Lezhima.Web层再增加一个名为“TestController”的控制器,用于向用户提供测试读写MongoDB操作的出入口,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Lezhima.Core; using Lezhima.Data.Interface; using Microsoft.AspNetCore.Mvc; namespace Lezhima.Web.Controllers { [Route("api/[controller]")] public class TestController : Controller { private readonly IMongoRepository<ActionLog> _IMongoRepository; public TestController(IMongoRepository<ActionLog> __IMongoRepository) { _IMongoRepository = __IMongoRepository; } /// <summary> /// 测试新增数据方法 /// </summary> /// <returns></returns> [HttpGet] public async Task<string> Add() { //创建两个不同企业ID的实体数据 var model1 = new ActionLog(); model1.CompanyId = Guid.Parse("B29BC831-A974-4114-90E2-0001E03FBCAF"); model1.ActionLogId = Guid.NewGuid(); model1.Context = "测试企业1"; model1.CreateTime = DateTime.Now; model1.UpdateTime = DateTime.Now; var model2 = new ActionLog(); model2.CompanyId = Guid.Parse("651bbe49-a4c8-4514-babb-897dad7065e3"); model2.ActionLogId = Guid.NewGuid(); model2.Context = "测试企业2"; model2.CreateTime = DateTime.Now; model2.UpdateTime = DateTime.Now; var list = new List<ActionLog>(); list.Add(model1); list.Add(model2); var group_list = list.GroupBy(p => p.CompanyId); var tableName = "ActionLog_" + DateTime.Now.ToString("yyyy-MM-dd"); foreach (var group in group_list) { var dbName = "ActionLog_" + group.FirstOrDefault().CompanyId.ToString(); await _IMongoRepository.Add(group.ToList(), dbName, tableName); } return "value1"; } /// <summary> /// 测试查询方法 /// </summary> /// <param name="companyId"></param> /// <returns></returns> [HttpGet("{companyId}")] public async Task<List<ActionLog>> Get(Guid companyId) { var dbName = "ActionLog_" + companyId.ToString(); var tableName = "ActionLog_" + DateTime.Now.ToString("yyyy-MM-dd"); var list = await _IMongoRepository.GetListAsync(p => p.Context.IndexOf("测试企业") > -1, dbName, tableName); return list; } } }
总结
1、MongoDB是开源的文档型非关系型数据库,支持JAVA/C#/Python等多种开发语言。
2、通过由MongoDB官方提供的两个API类库实现跟MongoDB通讯交互。
3、MongoDB不需要提前创建数据库与表结构,其会通过传递进去的数据结构自动判断是否需要维护库与表的结构,这个机制对我们项目的大部分场景都很实用。
4、最后再通过对Lezhima.Data层简单的封装后,使得面向业务层的调用非常简便。
声明
本文为作者原创,转载请备注出处与保留原文地址,谢谢。如文章能给您带来帮助,请点下推荐或关注,感谢您的支持!
在ASP.NET Core2上操作MongoDB就是能这么的简便酷爽(自动完成分库分表)的更多相关文章
-
C# Asp.net中简单操作MongoDB数据库(二)
C# Asp.net中简单操作MongoDB数据库(一) , mongodb数据库连接可以回顾上面的篇幅. 1.model类: public class BaseEntity { /// < ...
-
C# Asp.net中简单操作MongoDB数据库(一)
需要引用MongoDB.Driver.dll.MongoDB.Driver.core.dll.MongoDB.Bson.dll三个dll. 1.数据库连接: public class MongoDb ...
-
Mycat读写分离、主从切换、分库分表的操作记录
系统开发中,数据库是非常重要的一个点.除了程序的本身的优化,如:SQL语句优化.代码优化,数据库的处理本身优化也是非常重要的.主从.热备.分表分库等都是系统发展迟早会遇到的技术问题问题.Mycat是一 ...
-
DB层面上的设计 分库分表 读写分离 集群化 负载均衡
第1章 引言 随着互联网应用的广泛普及,海量数据的存储和访问成为了系统设计的瓶颈问题.对于一个大型的 互联网应用,每天几十亿的PV无疑对数据库造成了相当高的负载.对于系统的稳定性和扩展性造成了极大的 ...
-
MyBatis实现Mysql数据库分库分表操作和总结
前言 作为一个数据库,作为数据库中的一张表,随着用户的增多随着时间的推移,总有一天,数据量会大到一个难以处理的地步.这时仅仅一张表的数据就已经超过了千万,无论是查询还是修改,对于它的操作都会很耗时,这 ...
-
mongodb拆库分表脚本
脚本功能: 1. 将指定的报告文件按照指定的字段.切库切表策略切分 2. 将切分后的文件并发导入到对应的Mongodb中 3. 生成日志文件和done标识文件 使用手册: -h 打印帮助信息,并 ...
-
将asp.net core2.0项目部署在IIS上运行
原文:将asp.net core2.0项目部署在IIS上运行 前言: 与ASP.NET时代不同,ASP.NET Core不再是由IIS工作进程(w3wp.exe)托管,而是独立运行的.它独立运行在控 ...
-
在阿里云Windows Server 上部署ASP .NET CORE2.0项目
近期使用ASP.NET Core2.0对博客进行了重写,在部署到服务器时遇到了一些问题,来记录一下留用. 配置环境 安装 .Net Framework3.5 在IIS管理器上直接开启,这里总是失败,上 ...
-
ASP.NET Core2调用Azure云上的PowerBI报表展示
在开发企业应用中,报表功能是当之无愧的重头戏,如何将数据通过合适的报表呈现出来成为每个项目人员必需面临的问题.而找到一款合适的报表往往都需要考率价格.开发.风格.支撑等因素.那么,我在这里给大家介绍一 ...
随机推荐
-
3个div 宽度移入移出时变化
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
-
浅谈JS面向对象之创建对象
hello,everybody,今天要探讨的问题是JS面向对象,其实面向对象呢呢,一般是在大型项目上会采用,不过了解它对我们理解JS语言有很大的意义. 首先什么是面向对象编程(oop),就是用对象的思 ...
-
选择排序、插入排序、冒泡排序python实现
选择排序的时间复杂度为O(n^2),是不稳定的排序 冒泡排序的时间复杂度最好情况下为O(n),最坏情况下为O(n^2),平均情况下为O(n^2),是稳定的排序 插入排序的时间复杂度最好情况下为O(n) ...
-
处理 insert 字段内容包含 单引号 的问题
问题:postgreSQL insert 字段包含单引号,如:insert into table values('1001','tom'cat'),执行报错: 解决:将单引号替换为两个单引号,如 de ...
-
javascript小数相减会出现一长串的小数位数的原因
javascript小数相减会出现一长串的小数位数的原因 <script> var a='38.8'; var b='6.8'; alert(parseFloat(a)-parseFloa ...
-
与导航栏下控件的frame相关的edgesForExtendedLayout、translucent、extendedLayoutIncludesOpaqueBars、automaticallyAdjustsScrollViewInsets等几个属性的详解
在引入了导航控制器UINavigationController和分栏控制器UITabBarController之后,我们在设置控件的frame的时候就需要注意避开导航栏UINavigationBar ...
-
rabbitmq的安装与使用
1.RabbitMQ的安装,rabbitmq为erlang语言开发,所以先安装erlang语言开发包,现在电脑一般都是64位的,所以下载64位的都行了.红色框可以选择版本,箭头选择64位的进行下载.下 ...
-
Eclipse开发Web常见异常
1.java.lang.IllegalStateException: Web app root system property already set to different value 错误原因: ...
-
SpringBoot------注解把配置文件自动映射到属性和实体类
1.映射到属性 package top.ytheng.demo.controller; import org.springframework.beans.factory.annotation.Valu ...
-
Studio更新
其实最主要的是下面三个步骤: 1.更新As工程为3.0 2.必须升级gradle到4.0以上 3.buildToolsVersion升级到26.0.0 4.在gradle.properties中配置版 ...