博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MongoDB在实际项目中的使用
阅读量:4558 次
发布时间:2019-06-08

本文共 12635 字,大约阅读时间需要 42 分钟。

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了。

这个项目从2011年到现在已经断断续续维持了5年了,从MongoDB1.0到MongoDB3.2,这个工具和MongoDB一起成长起来的。将近200个Star,最近又有两个两个朋友贡献了代码(现在使用C#开发Winform的人真的不多了),让我感到很欣慰。
期间进行了一次比较大的重构(由于自己对于软件设计的理解的提高,以及从盲目的追求快速添加功能到追求整个项目代码的合理,才下决心进行了一次伤筋动骨的重构,当然现在再看,这次重构很重要,但是代码仍然还是有问题的,绝非完美。)
在开发 的过程中,整个MONGODB数据库的查看都使用了这个工具,同时在使用中发现了一些BUG,也进行了一些改善。当然我现在也不敢保证BUG全部都清除干净了。如果发现BUG,请和我联系。
原本打算使用Mono进行跨平台的,但是Mono对于Winform的支持并不好,所以虽然这个工具可以在Mac的OSX上运行,但是最好还是老老实实在Windows下运行比较好。发一张工具的界面图片,在OSX上截WIndows远程桌面的图。
Thumbnail?filename=00000001_20160501212726_%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202016-05-01%20%E4%B8%8B%E5%8D%889.24.42.png

C#驱动程序的再包装

虽然官方的C#已经和不错了,虽然MongoDB原生支持ORM的。文档型对象就是OOP对象了。

但是资深码农都会自己再写一些操作数据库的Helper方法。为自己定制的一套从EntityBase到ORM的方法。
(关于时区的设定,其实可以在系列化设定中完成)

using System;using MongoDB.Bson.Serialization.Attributes;namespace InfraStructure.DataBase{    ///     ///     实体    ///     没有物理删除,所以自增SN是安全的    ///     public abstract class EntityBase    {        ///         ///     创建时间        ///         [BsonDateTimeOptions(Kind = DateTimeKind.Local)] public DateTime CreateDateTime;        ///         ///     创建者        ///     [这里可以是用户名,亦可是账号]        ///         public string CreateUser;        ///         ///     删除标记        ///         public bool IsDel;        ///         ///     序列号        ///         [BsonId] public string Sn;        ///         ///     更新时间        ///         [BsonDateTimeOptions(Kind = DateTimeKind.Local)] public DateTime UpdateDateTime;        ///         ///     更新者        ///         public string UpdateUser;        ///         ///     获得表名称        ///         /// 
public abstract string GetCollectionName(); /// /// 获得主键前缀 /// ///
public abstract string GetPrefix(); /// /// 序列号格式 /// 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    {        ///         ///     服务器        ///         private static MongoServer _innerServer;        ///         ///     链接字符串        ///         private static readonly string Connectionstring = @"mongodb://localhost:";        ///         ///     初始化MongoDB        ///         /// 除去Logger以外        ///         ///         /// 
public static bool Init(string port = "28030") { try { _innerServer = new MongoClient(Connectionstring + port).GetServer(); _innerServer.Connect(); return true; } catch (Exception) { return false; } } /// /// 保存文件 /// /// /// /// ///
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; } /// /// 保存文件 /// /// /// /// ///
public static string InsertFile(HttpPostedFile file, string ownerId, string databaseType) { return InsertFile(new HttpPostedFileWrapper(file) as HttpPostedFileBase, ownerId, databaseType); } /// /// /// /// /// /// /// ///
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; } /// /// 保存流为固定文件名 /// /// /// /// 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); } /// /// 获得文件 /// /// /// 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); } } /// /// 用户上传图片 /// /// /// /// /// ///
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; } /// /// Mongo文件结构 /// public struct DbFileInfo { /// /// 文件名 /// public string FileName; /// /// 数据库文件名 /// public string DbFileName; } /// /// 文件备份 /// /// 文件列表 /// 备份路径。注意以斜线结尾 /// 数据库名称 public static void BackUpFiles(List
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进行全文检索的。
全文检索的索引设定和使用:

///         ///     设置Text索引        ///         ///         ///         ///         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);        }        ///         /// 全文检索        ///         ///         ///         ///         ///         /// 
public static List
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
(textSearchQuery); var resultDocumentList = result.SetLimit(limit).ToList(); return resultDocumentList; }

内置的聚合操作

MongoDB提供了一些内置的聚合函数,通过驱动程序可以直接使用

///         /// Distinct        ///         ///         ///         ///         /// 
public static List
Distinct(string collectionName, string FieldName, IMongoQuery query = null) { MongoCollection col = GetDatabaseByType(_defaultDatabaseName).GetCollection(collectionName); var DistinctResult = col.Distinct(FieldName, query); var result = new List
(); foreach (BsonValue item in DistinctResult) { result.Add(item.AsString); } return result; }

使用Javascript进行聚合操作

MongoDB是可以使用js进行聚合操作的。由于MongoDB内置了Google的V8引擎,所以可以通过运行自定义的Js片段来进行一些聚合操作。

///         /// GroupByCount        ///         ///         ///         /// 
public static Dictionary
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
(); 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分钟自动清除操作的。

///         ///     设定数据缓存时间(以创建时间为基础)        ///         ///         ///         ///         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);        }

转载于:https://www.cnblogs.com/TextEditor/p/5454168.html

你可能感兴趣的文章
Shell 正则表达式
查看>>
Docker run命令参数整理
查看>>
qt-opencv配置mingw编译器
查看>>
CSS之Medial Queries的另一用法:实现IE hack的方法
查看>>
linux-CentOS6.4下安装oracle11g详解
查看>>
实力为王 八年DBA经验谈
查看>>
2-sat 问题 【例题 Flags(2-sat+线段树优化建图)】
查看>>
ext3.2 右击动态添加node的treepanel
查看>>
Database links
查看>>
1035 插入与归并(25 分)
查看>>
STL中排序函数的用法(Qsort,Sort,Stable_sort,Partial_sort,List::sort)
查看>>
如何解决php 生成验证码图片不显示问题
查看>>
PHP,javascript实现大文件上传
查看>>
c#图像处理算法学习
查看>>
webApi之FromUri和FromBody区别
查看>>
【SoapUI】http接口测试
查看>>
各种工具网站
查看>>
数据库事务
查看>>
xe7 控件升级
查看>>
TFrame bug
查看>>