MongoDB在实际项目中的使用
MongoDB简介
MongoDB是近些年来流行起来的NoSql的代表,和传统数据库最大的区别是支持文档型数据库。
当然,现在的一些数据库通过自定义复合类型,可变长数组等手段也可以模拟文档型数据库。
例如在PostgreSQL中,以下是一个复合类型的例子
CREATE TYPE complex AS (
r double precision,
i double precision
);
CREATE TYPE inventory_item AS (
name text,
supplier_id integer,
price numeric
);
数组的定义如下
array[1,2] --一维数组
array[[1,2],[3,5]] --二维数组
当然,MongoDB生来就是文档型数据库,自然在应用层面对数据操作非常友好。
- 使用了一套聚合框架来进行专业的聚合操作,和SQL语言相比,可以支持更加细致的操作
- 可以使用JavaScript编写MapReduce函数进行数据统计操作,在分布式框架下适合处理大数据
当然,你也可以将MongoDB当做普通的关系型数据库那样使用。但是这样就无法定义View(如果要使用View这样的功能,还是老老实实将MongoDB当做文档型数据库来使用吧)
在 http://codesnippet.info/ 建站过程中,有些基础数据是简单的关系型数据,有些是缓存用文档型数据。
MongoDB的管理工具
这里我就推荐自己开发的工具MongoCola了。
MongoCola项目Github地址
这个项目从2011年到现在已经断断续续维持了5年了,从MongoDB1.0到MongoDB3.2,这个工具和MongoDB一起成长起来的。将近200个Star,最近又有两个两个朋友贡献了代码(现在使用C#开发Winform的人真的不多了),让我感到很欣慰。
期间进行了一次比较大的重构(由于自己对于软件设计的理解的提高,以及从盲目的追求快速添加功能到追求整个项目代码的合理,才下决心进行了一次伤筋动骨的重构,当然现在再看,这次重构很重要,但是代码仍然还是有问题的,绝非完美。)
在开发 www.codesnippet.info 的过程中,整个MONGODB数据库的查看都使用了这个工具,同时在使用中发现了一些BUG,也进行了一些改善。当然我现在也不敢保证BUG全部都清除干净了。如果发现BUG,请和我联系。
原本打算使用Mono进行跨平台的,但是Mono对于Winform的支持并不好,所以虽然这个工具可以在Mac的OSX上运行,但是最好还是老老实实在Windows下运行比较好。发一张工具的界面图片,在OSX上截WIndows远程桌面的图。
![](http://codesnippet.info/FileSystem/Thumbnail?filename=00000001_20160501212726_屏幕快照 2016-05-01 下午9.24.42.png)
C#驱动程序的再包装
虽然官方的C#已经和不错了,虽然MongoDB原生支持ORM的。文档型对象就是OOP对象了。
但是资深码农都会自己再写一些操作数据库的Helper方法。为自己定制的一套从EntityBase到ORM的方法。
(关于时区的设定,其实可以在系列化设定中完成)
using System;
using MongoDB.Bson.Serialization.Attributes;
namespace InfraStructure.DataBase
{
/// <summary>
/// 实体
/// 没有物理删除,所以自增SN是安全的
/// </summary>
public abstract class EntityBase
{
/// <summary>
/// 创建时间
/// </summary>
[BsonDateTimeOptions(Kind = DateTimeKind.Local)] public DateTime CreateDateTime;
/// <summary>
/// 创建者
/// [这里可以是用户名,亦可是账号]
/// </summary>
public string CreateUser;
/// <summary>
/// 删除标记
/// </summary>
public bool IsDel;
/// <summary>
/// 序列号
/// </summary>
[BsonId] public string Sn;
/// <summary>
/// 更新时间
/// </summary>
[BsonDateTimeOptions(Kind = DateTimeKind.Local)] public DateTime UpdateDateTime;
/// <summary>
/// 更新者
/// </summary>
public string UpdateUser;
/// <summary>
/// 获得表名称
/// </summary>
/// <returns></returns>
public abstract string GetCollectionName();
/// <summary>
/// 获得主键前缀
/// </summary>
/// <returns></returns>
public abstract string GetPrefix();
/// <summary>
/// 序列号格式
/// </summary>
public const string SnFormat = "D8";
}
}
ORM的增删改也无非就是将驱动的数据库操作重新定制了一下而已。
具体代码可以在本网站的开源项目中找到
数据库操作辅助类
MongoDB的序列化设定 (干货)
- 场景一:由于类定义变更,某个字段不需要了,但是如果不进行设定的话,发序列化会出错,某个数据库字段没有配置的实体字段(IgnoreExtraElementsConvention)
- 场景二:在序列化的时候,为了节省空间,希望字段为空的时候,不进行序列化。(IgnoreIfNullConvention)
- 场景三:日期型的数据,序列化的时候,希望可以指定时区(RegisterSerializer)
//http://mongodb.github.io/mongo-csharp-driver/1.10/serialization/
var pack = new ConventionPack();
pack.Add(new IgnoreExtraElementsConvention(true));
pack.Add(new IgnoreIfNullConvention(true));
ConventionRegistry.Register("CustomElementsConvention", pack, t => { return true; });
//DateTime Localize
BsonSerializer.RegisterSerializer(typeof(DateTime), new DateTimeSerializer(DateTimeKind.Local));
return true;
当然,你也可以对某个日期型字段单独指定时区,或者将某个字段定义为主键。详细请参考上文提到的 [BsonId] 和 [BsonDateTimeOptions(Kind = DateTimeKind.Local)] 特性。
FileStorage
MongoDB虽然可以使用FileSystem,但是由于是内存型数据库,可能会大量消耗内存资源。
这里贴一下FileSystemHelper,但是不建议大型项目在没有足够资源的情况下使用!!
using System;
using System.Collections.Generic;
using System.Web;
using MongoDB.Driver.GridFS;
using System.IO;
using MongoDB.Driver;
using System.Drawing.Imaging;
using System.Drawing;
namespace InfraStructure.Storage
{
public static class MongoStorage
{
/// <summary>
/// 服务器
/// </summary>
private static MongoServer _innerServer;
/// <summary>
/// 链接字符串
/// </summary>
private static readonly string Connectionstring = @"mongodb://localhost:";
/// <summary>
/// 初始化MongoDB
/// </summary>
/// <param name="dbList">除去Logger以外</param>
/// <param name="defaultDbName"></param>
/// <param name="port"></param>
/// <returns></returns>
public static bool Init(string port = "28030")
{
try
{
_innerServer = new MongoClient(Connectionstring + port).GetServer();
_innerServer.Connect();
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// 保存文件
/// </summary>
/// <param name="file"></param>
/// <param name="ownerId"></param>
/// <param name="databaseType"></param>
/// <returns></returns>
public static string InsertFile(HttpPostedFileBase file, string ownerId, string databaseType)
{
var mongofilename = ownerId + "_" + DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + file.FileName;
var innerFileServer = _innerServer.GetDatabase(databaseType);
var gfs = innerFileServer.GetGridFS(new MongoGridFSSettings());
gfs.Upload(file.InputStream, mongofilename);
return mongofilename;
}
/// <summary>
/// 保存文件
/// </summary>
/// <param name="file"></param>
/// <param name="ownerId"></param>
/// <param name="databaseType"></param>
/// <returns></returns>
public static string InsertFile(HttpPostedFile file, string ownerId, string databaseType)
{
return InsertFile(new HttpPostedFileWrapper(file) as HttpPostedFileBase, ownerId, databaseType);
}
/// <summary>
///
/// </summary>
/// <param name="file"></param>
/// <param name="fileName"></param>
/// <param name="ownerId"></param>
/// <param name="databaseType"></param>
/// <returns></returns>
public static string InsertFile(Stream file, string fileName, string ownerId, string databaseType)
{
var mongofilename = ownerId + "_" + DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + fileName;
var innerFileServer = _innerServer.GetDatabase(databaseType);
var gfs = innerFileServer.GetGridFS(new MongoGridFSSettings());
gfs.Upload(file, mongofilename);
return mongofilename;
}
/// <summary>
/// 保存流为固定文件名
/// </summary>
/// <param name="file"></param>
/// <param name="fixedFilename"></param>
/// <param name="databaseType"></param>
public static void InsertStreamWithFixFileName(Stream file, string fixedFilename, string databaseType)
{
var innerFileServer = _innerServer.GetDatabase(databaseType);
var gfs = innerFileServer.GetGridFS(new MongoGridFSSettings());
gfs.Upload(file, fixedFilename);
}
/// <summary>
/// 获得文件
/// </summary>
/// <param name="stream"></param>
/// <param name="filename"></param>
public static void GetFile(Stream stream, string filename, string databaseType)
{
var innerFileServer = _innerServer.GetDatabase(databaseType);
var gfs = innerFileServer.GetGridFS(new MongoGridFSSettings());
if (gfs.Exists(filename))
{
gfs.Download(stream, filename);
}
}
/// <summary>
/// 用户上传图片
/// </summary>
/// <param name="file"></param>
/// <param name="ownerId"></param>
/// <param name="weight"></param>
/// <param name="height"></param>
/// <returns></returns>
public static string InsertImage(HttpPostedFileBase file, string ownerId, int weight = 64, int height = 64)
{
var fileName = file.FileName;
var originalImage = Image.FromStream(file.InputStream);
var thumbImage = originalImage.GetThumbnailImage(weight, height, null, IntPtr.Zero);
using (var ms = new MemoryStream())
{
thumbImage.Save(ms, ImageFormat.Jpeg);
//必须将位置重置
ms.Position = 0;
fileName = InsertFile(ms, fileName, ownerId, string.Empty);
}
return fileName;
}
/// <summary>
/// Mongo文件结构
/// </summary>
public struct DbFileInfo
{
/// <summary>
/// 文件名
/// </summary>
public string FileName;
/// <summary>
/// 数据库文件名
/// </summary>
public string DbFileName;
}
/// <summary>
/// 文件备份
/// </summary>
/// <param name="fileList">文件列表</param>
/// <param name="path">备份路径。注意以斜线结尾</param>
/// <param name="databaseType">数据库名称</param>
public static void BackUpFiles(List<DbFileInfo> fileList, string path, string databaseType)
{
var innerFileServer = _innerServer.GetDatabase(databaseType);
foreach (var item in fileList)
{
var gfs = innerFileServer.GetGridFS(new MongoGridFSSettings());
gfs.Download(path + item.FileName, item.DbFileName);
}
}
}
}
全文检索
如果您的项目是英文项目,可以不需要第三方库,直接在MongoDB中完成全文检索。前提条件是为数据集设定文本索引
如果您的项目是中文项目,必须使用企业版的MongoDB,加上第三方的分词库,才能实现全文检索
http://codesnippet.info/ 使用的是ElasticSearch进行全文检索的。
使用NEST操作ElasticSearch进行全文检索
全文检索的索引设定和使用:
/// <summary>
/// 设置Text索引
/// </summary>
/// <param name="collectionName"></param>
/// <param name="FieldName"></param>
/// <param name="database"></param>
public static void SetTextIndex(string collectionName, string FieldName, string database = "")
{
if (string.IsNullOrEmpty(database)) database = _defaultDatabaseName;
MongoCollection col = GetDatabaseByType(database).GetCollection(collectionName);
if (col.IndexExistsByName(FieldName))
{
return;
}
var option = new IndexOptionsBuilder();
option.SetName(FieldName);
var indexkeys = new IndexKeysBuilder();
indexkeys.Text(new string[] { FieldName });
col.CreateIndex(indexkeys, option);
}
/// <summary>
/// 全文检索
/// </summary>
/// <param name="collectionName"></param>
/// <param name="key"></param>
/// <param name="caseSensitive"></param>
/// <param name="limit"></param>
/// <returns></returns>
public static List<BsonDocument> SearchText(string collectionName, string key, bool caseSensitive, int limit, IMongoQuery query = null)
{
//检索关键字
var textSearchOption = new TextSearchOptions();
textSearchOption.CaseSensitive = caseSensitive;
var textSearchQuery = Query.Text(key, textSearchOption);
if (query != null)
{
textSearchQuery = Query.And(textSearchQuery, query);
}
MongoCollection col = GetDatabaseByType(_defaultDatabaseName).GetCollection(collectionName);
var result = col.FindAs<BsonDocument>(textSearchQuery);
var resultDocumentList = result.SetLimit(limit).ToList();
return resultDocumentList;
}
内置的聚合操作
MongoDB提供了一些内置的聚合函数,通过驱动程序可以直接使用
/// <summary>
/// Distinct
/// </summary>
/// <param name="collectionName"></param>
/// <param name="FieldName"></param>
/// <param name="query"></param>
/// <returns></returns>
public static List<string> Distinct(string collectionName, string FieldName, IMongoQuery query = null)
{
MongoCollection col = GetDatabaseByType(_defaultDatabaseName).GetCollection(collectionName);
var DistinctResult = col.Distinct(FieldName, query);
var result = new List<string>();
foreach (BsonValue item in DistinctResult)
{
result.Add(item.AsString);
}
return result;
}
使用Javascript进行聚合操作
MongoDB是可以使用js进行聚合操作的。由于MongoDB内置了Google的V8引擎,所以可以通过运行自定义的Js片段来进行一些聚合操作。
/// <summary>
/// GroupByCount
/// </summary>
/// <param name="collectionName"></param>
/// <param name="FieldName"></param>
/// <returns></returns>
public static Dictionary<string, int> GroupCount(string collectionName, string FieldName, IMongoQuery query = null)
{
MongoCollection col = GetDatabaseByType(_defaultDatabaseName).GetCollection(collectionName);
GroupArgs g = new GroupArgs();
var groupdoc = new GroupByDocument();
groupdoc.Add(FieldName, true);
g.KeyFields = groupdoc;
g.ReduceFunction = new BsonJavaScript("function(obj,prev){ prev.count++;}");
g.Initial = new BsonDocument().Add("count", 0);
if (query != null)
{
g.Query = query;
}
var GroupResult = col.Group(g);
var result = new Dictionary<string, int>();
foreach (BsonDocument item in GroupResult)
{
result.Add(item.GetElement(FieldName).Value.ToString(), (int)item.GetElement("count").Value.AsDouble);
}
return result;
}
TTL索引
使用MongoDB的TTL(TimeToLive)索引,可以实现定时缓存功能,数据经过指定时间后就自动从数据库里面删除。
很多缓存数据现在就是用TTL索引实现15分钟自动清除操作的。
/// <summary>
/// 设定数据缓存时间(以创建时间为基础)
/// </summary>
/// <param name="collectionName"></param>
/// <param name="ExpiresMinute"></param>
/// <param name="database"></param>
public static void SetCacheTime(string collectionName, int ExpiresMinute, string database = "")
{
if (string.IsNullOrEmpty(database)) database = _defaultDatabaseName;
MongoCollection col = GetDatabaseByType(database).GetCollection(collectionName);
if (col.IndexExistsByName("Cache"))
{
col.DropIndexByName("Cache");
}
var option = new IndexOptionsBuilder();
option.SetTimeToLive(new TimeSpan(0, ExpiresMinute, 0));
option.SetName("Cache");
var indexkeys = new IndexKeysBuilder();
indexkeys.Ascending(new string[] { nameof(EntityBase.CreateDateTime) });
col.CreateIndex(indexkeys, option);
}
MongoDB在实际项目中的使用的更多相关文章
- MongoDB在实际项目
MongoDB在实际项目中的使用 MongoDB简介 MongoDB是近些年来流行起来的NoSql的代表,和传统数据库最大的区别是支持文档型数据库.当然,现在的一些数据库通过自定义复合类型,可变长 ...
- 使用MongoDB在项目中实际运用
一.MongoDB,一个数据库,我们怎么去使用它呢?我们首先了解一下什么是MongoDb 官网的介绍是:MongoDB是专为可扩展性,高性能和高可用性而设计的数据库.它可以从单服务器部署扩展到大型.复 ...
- .Net Core ORM选择之路,哪个才适合你 通用查询类封装之Mongodb篇 Snowflake(雪花算法)的JavaScript实现 【开发记录】如何在B/S项目中使用中国天气的实时天气功能 【开发记录】微信小游戏开发入门——俄罗斯方块
.Net Core ORM选择之路,哪个才适合你 因为老板的一句话公司项目需要迁移到.Net Core ,但是以前同事用的ORM不支持.Net Core 开发过程也遇到了各种坑,插入条数多了也特别 ...
- NoSql非关系型数据库之MongoDB应用(三):MongoDB在项目中的初步应用
业精于勤,荒于嬉:行成于思,毁于随. 我们可以结合相关的IDE做一个简单的增删改查了,实现MongoDB在项目中的初步应用. 前提是安装了MongoDB服务和MongoDB可视化工具,没有安装的可以点 ...
- Mongo基础使用,以及在Express项目中使用Mongoose
MongoDB的基本使用 MongoDB特点: 使用BSON存储数据 支持相对丰富的查询操作(相对其他nosql数据库) 支持索引 副本集(支持多个实例/多个服务器运行同个数据库) 分片(数据库水平扩 ...
- 在WebStorm环境中给nodejs项目中添加packages
照前文 http://www.cnblogs.com/wtang/articles/4133820.html 给电脑设置了WebStorm的IDE的nodejs开发环境.新建了个express的网站 ...
- 夺命雷公狗---node.js---19之项目的构建在node+express+mongo的博客项目4mongodb在项目中的基本引入
首先我们在命令行下先建立这个库: 然后我们在项目中引入mongodb的模块: var MongoClient = require('mongodb').MongoClient; var DB_STR ...
- 在.NET项目中使用PostSharp,使用CacheManager实现多种缓存框架的处理
在前面几篇随笔中,介绍了PostSharp的使用,以及整合MemoryCache,<在.NET项目中使用PostSharp,实现AOP面向切面编程处理>.<在.NET项目中使用Pos ...
- 使用反射+策略模式代替项目中大量的switch case判断
我这里的业务场景是根据消息类型将离线消息存入mongoDB不同的collection中.其中就涉及到大量的分支判断,为了增强代码的可读性和可维护性,对之前的代码进行了重构. 先对比一下使用反射+策略模 ...
随机推荐
- 基于Oracle的SQL优化(社区万众期待 数据库优化扛鼎巨著)
基于Oracle的SQL优化(社区万众期待数据库优化扛鼎巨著) 崔华 编 ISBN 978-7-121-21758-6 2014年1月出版 定价:128.00元 856页 16开 编辑推荐 本土O ...
- win环境安装python爬虫框架scrapy
#官网下载python for windows #https://www.python.org/downloads/ #安装后在“计算机->属性->高级系统设置->环境变量-> ...
- struts1的一些基本用法和操作
入职两周了,项目是用struts1+ibatis框架搭建的,数据库是oracle,其他还行,关键是struts1之前没用用过,所以只好在网上狂查文档,最后大致整理了一些struts1的基本使用方法. ...
- 快速入门系列--GIT版本控制工具
由于GIT刚刚开始使用不久,经常会在Merge时出现没有change-id的情况,在结合gerrit使用时,经常出现不能提交的情形,使得自己很困扰.最近有次熬夜加班,在代码完成后,由于多人在很短时间内 ...
- Android入门(十五)通知
原文链接:http://www.orlion.ga/663/ 1.通知的基本用法 创建通知的步骤,首先需要一个NotificationManager来对通知进行管理,可以调用Context的getSy ...
- Abp公共连接和事务管理方法
Conection 和事务管理在使用数据库的应用中是一个最重要的概念.当你打开一个连接,开始一个事务,如何来处理这些连接等等. 您也许知道,.NET使用了连接池.所以,创建一个连接实际上是从连接池里得 ...
- Linq(一)
Linq是c#设计者们在c#3.0中新添加的语法:查询表达式.使用查询表达式,很多标准查询操作符都能转化成更容易理解的代码,也就是和SQL风格非常接近的代码. 在介绍Linq之前,先介绍下泛型集合IE ...
- php基础教程-语法
PHP 脚本可放置于文档中的任何位置.PHP 脚本以 <?php 开头,以 ?> 结尾: <?php // 此处是 PHP 代码 ?> PHP 文件的默认文件扩展名是 &quo ...
- 2014PPTV-题解
今天在看PPTV几道题目,顺便联系起红宝书<JavaScript高级程序设计>一起看了起来. 1. var msg = 'hello';//顶级作用域windwo下有个变量msg func ...
- 面试题目: PHP 有哪些优缺点?
当面试官噼里啪啦的问你一大堆问题后,突然问你,PHP有哪些优缺点?你蒙了没? 反正我是蒙了,不管你信不信! 现在,关于PHP优缺点,大致的说几点: 1. 语法简单的,上手很快,而且还有很多很便捷的开 ...