首页 文章资讯内容详情

MongoDB在实际项目中的使用

2026-06-01 4 花语

本文内容纲要:

-MongoDB简介 -MongoDB的管理工具 -C#驱动程序的再包装 -MongoDB的序列化设定(干货) -FileStorage -全文检索 -内置的聚合操作 -使用Javascript进行聚合操作 -TTL索引

MongoDB简介

MongoDB是近些年来流行起来的NoSql的代表,和传统数据库最大的区别是支持文档型数据库。

当然,现在的一些数据库通过自定义复合类型,可变长数组等手段也可以模拟文档型数据库。

例如在PostgreSQL中,以下是一个复合类型的例子 CREATETYPEcomplexAS( rdoubleprecision, idoubleprecision ); CREATETYPEinventory_itemAS( nametext, supplier_idinteger, pricenumeric );

数组的定义如下

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的方法。

(关于时区的设定,其实可以在系列化设定中完成) usingSystem; usingMongoDB.Bson.Serialization.Attributes; namespaceInfraStructure.DataBase { ///<summary> ///实体 ///没有物理删除,所以自增SN是安全的 ///</summary> publicabstractclassEntityBase { ///<summary> ///创建时间 ///</summary> [BsonDateTimeOptions(Kind=DateTimeKind.Local)]publicDateTimeCreateDateTime; ///<summary> ///创建者 ///[这里可以是用户名,亦可是账号] ///</summary> publicstringCreateUser; ///<summary> ///删除标记 ///</summary> publicboolIsDel; ///<summary> ///序列号 ///</summary> [BsonId]publicstringSn; ///<summary> ///更新时间 ///</summary> [BsonDateTimeOptions(Kind=DateTimeKind.Local)]publicDateTimeUpdateDateTime; ///<summary> ///更新者 ///</summary> publicstringUpdateUser; ///<summary> ///获得表名称 ///</summary> ///<returns></returns> publicabstractstringGetCollectionName(); ///<summary> ///获得主键前缀 ///</summary> ///<returns></returns> publicabstractstringGetPrefix(); ///<summary> ///序列号格式 ///</summary> publicconststringSnFormat="D8"; } }

ORM的增删改也无非就是将驱动的数据库操作重新定制了一下而已。

具体代码可以在本网站的开源项目中找到

数据库操作辅助类

MongoDB的序列化设定(干货)

场景一:由于类定义变更,某个字段不需要了,但是如果不进行设定的话,发序列化会出错,某个数据库字段没有配置的实体字段(IgnoreExtraElementsConvention)

场景二:在序列化的时候,为了节省空间,希望字段为空的时候,不进行序列化。(IgnoreIfNullConvention)

场景三:日期型的数据,序列化的时候,希望可以指定时区(RegisterSerializer)

//http://mongodb.github.io/mongo-csharp-driver/1.10/serialization/ varpack=newConventionPack(); pack.Add(newIgnoreExtraElementsConvention(true)); pack.Add(newIgnoreIfNullConvention(true)); ConventionRegistry.Register("CustomElementsConvention",pack,t=>{returntrue;}); //DateTimeLocalize

BsonSerializer.RegisterSerializer(typeof(DateTime),newDateTimeSerializer(DateTimeKind.Local)); returntrue;

当然,你也可以对某个日期型字段单独指定时区,或者将某个字段定义为主键。详细请参考上文提到的[BsonId]和[BsonDateTimeOptions(Kind=DateTimeKind.Local)]特性。

FileStorage

MongoDB虽然可以使用FileSystem,但是由于是内存型数据库,可能会大量消耗内存资源。

这里贴一下FileSystemHelper,但是不建议大型项目在没有足够资源的情况下使用!!

usingSystem; usingSystem.Collections.Generic; usingSystem.Web; usingMongoDB.Driver.GridFS; usingSystem.IO; usingMongoDB.Driver; usingSystem.Drawing.Imaging; usingSystem.Drawing; namespaceInfraStructure.Storage { publicstaticclassMongoStorage { ///<summary> ///服务器 ///</summary> privatestaticMongoServer_innerServer; ///<summary> ///链接字符串 ///</summary> privatestaticreadonlystringConnectionstring=@"mongodb://localhost:"; ///<summary> ///初始化MongoDB ///</summary> ///<paramname="dbList">除去Logger以外</param> ///<paramname="defaultDbName"></param> ///<paramname="port"></param> ///<returns></returns> publicstaticboolInit(stringport="28030") { try { _innerServer=newMongoClient(Connectionstring+port).GetServer(); _innerServer.Connect(); returntrue; } catch(Exception) { returnfalse; } } ///<summary> ///保存文件 ///</summary> ///<paramname="file"></param> ///<paramname="ownerId"></param> ///<paramname="databaseType"></param> ///<returns></returns> publicstaticstringInsertFile(HttpPostedFileBasefile,stringownerId,stringdatabaseType) { varmongofilename=ownerId+"_"+DateTime.Now.ToString("yyyyMMddHHmmss")+"_"+file.FileName; varinnerFileServer=_innerServer.GetDatabase(databaseType); vargfs=innerFileServer.GetGridFS(newMongoGridFSSettings()); gfs.Upload(file.InputStream,mongofilename); returnmongofilename; } ///<summary> ///保存文件 ///</summary> ///<paramname="file"></param> ///<paramname="ownerId"></param> ///<paramname="databaseType"></param> ///<returns></returns> publicstaticstringInsertFile(HttpPostedFilefile,stringownerId,stringdatabaseType) { returnInsertFile(newHttpPostedFileWrapper(file)asHttpPostedFileBase,ownerId,databaseType); } ///<summary> /// ///</summary> ///<paramname="file"></param> ///<paramname="fileName"></param> ///<paramname="ownerId"></param> ///<paramname="databaseType"></param> ///<returns></returns> publicstaticstringInsertFile(Streamfile,stringfileName,stringownerId,stringdatabaseType) { varmongofilename=ownerId+"_"+DateTime.Now.ToString("yyyyMMddHHmmss")+"_"+fileName; varinnerFileServer=_innerServer.GetDatabase(databaseType); vargfs=innerFileServer.GetGridFS(newMongoGridFSSettings()); gfs.Upload(file,mongofilename); returnmongofilename; } ///<summary> ///保存流为固定文件名 ///</summary> ///<paramname="file"></param> ///<paramname="fixedFilename"></param> ///<paramname="databaseType"></param> publicstaticvoidInsertStreamWithFixFileName(Streamfile,stringfixedFilename,stringdatabaseType) { varinnerFileServer=_innerServer.GetDatabase(databaseType); vargfs=innerFileServer.GetGridFS(newMongoGridFSSettings()); gfs.Upload(file,fixedFilename); } ///<summary> ///获得文件 ///</summary> ///<paramname="stream"></param> ///<paramname="filename"></param> publicstaticvoidGetFile(Streamstream,stringfilename,stringdatabaseType) { varinnerFileServer=_innerServer.GetDatabase(databaseType); vargfs=innerFileServer.GetGridFS(newMongoGridFSSettings()); if(gfs.Exists(filename)) { gfs.Download(stream,filename); } } ///<summary> ///用户上传图片 ///</summary> ///<paramname="file"></param> ///<paramname="ownerId"></param> ///<paramname="weight"></param> ///<paramname="height"></param> ///<returns></returns> publicstaticstringInsertImage(HttpPostedFileBasefile,stringownerId,intweight=64,intheight=64) { varfileName=file.FileName; varoriginalImage=Image.FromStream(file.InputStream); varthumbImage=originalImage.GetThumbnailImage(weight,height,null,IntPtr.Zero); using(varms=newMemoryStream()) { thumbImage.Save(ms,ImageFormat.Jpeg); //必须将位置重置 ms.Position=0; fileName=InsertFile(ms,fileName,ownerId,string.Empty); } returnfileName; } ///<summary> ///Mongo文件结构 ///</summary> publicstructDbFileInfo { ///<summary> ///文件名 ///</summary> publicstringFileName; ///<summary> ///数据库文件名 ///</summary> publicstringDbFileName; } ///<summary> ///文件备份 ///</summary> ///<paramname="fileList">文件列表</param> ///<paramname="path">备份路径。注意以斜线结尾</param> ///<paramname="databaseType">数据库名称</param> publicstaticvoidBackUpFiles(List<DbFileInfo>fileList,stringpath,stringdatabaseType) { varinnerFileServer=_innerServer.GetDatabase(databaseType); foreach(variteminfileList) { vargfs=innerFileServer.GetGridFS(newMongoGridFSSettings()); gfs.Download(path+item.FileName,item.DbFileName); } } } }

全文检索

如果您的项目是英文项目,可以不需要第三方库,直接在MongoDB中完成全文检索。前提条件是为数据集设定文本索引

如果您的项目是中文项目,必须使用企业版的MongoDB,加上第三方的分词库,才能实现全文检索

http://codesnippet.info/使用的是ElasticSearch进行全文检索的。

使用NEST操作ElasticSearch进行全文检索

全文检索的索引设定和使用: ///<summary> ///设置Text索引 ///</summary> ///<paramname="collectionName"></param> ///<paramname="FieldName"></param> ///<paramname="database"></param> publicstaticvoidSetTextIndex(stringcollectionName,stringFieldName,stringdatabase="") { if(string.IsNullOrEmpty(database))database=_defaultDatabaseName; MongoCollectioncol=GetDatabaseByType(database).GetCollection(collectionName); if(col.IndexExistsByName(FieldName)) { return; } varoption=newIndexOptionsBuilder(); option.SetName(FieldName); varindexkeys=newIndexKeysBuilder(); indexkeys.Text(newstring[]{FieldName}); col.CreateIndex(indexkeys,option); } ///<summary> ///全文检索 ///</summary> ///<paramname="collectionName"></param> ///<paramname="key"></param> ///<paramname="caseSensitive"></param> ///<paramname="limit"></param> ///<returns></returns> publicstaticList<BsonDocument>SearchText(stringcollectionName,stringkey,boolcaseSensitive,intlimit,IMongoQueryquery=null) { //检索关键字 vartextSearchOption=newTextSearchOptions(); textSearchOption.CaseSensitive=caseSensitive; vartextSearchQuery=Query.Text(key,textSearchOption); if(query!=null) { textSearchQuery=Query.And(textSearchQuery,query); } MongoCollectioncol=GetDatabaseByType(_defaultDatabaseName).GetCollection(collectionName); varresult=col.FindAs<BsonDocument>(textSearchQuery); varresultDocumentList=result.SetLimit(limit).ToList(); returnresultDocumentList; }

内置的聚合操作

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

///<summary> ///Distinct ///</summary> ///<paramname="collectionName"></param> ///<paramname="FieldName"></param> ///<paramname="query"></param> ///<returns></returns> publicstaticList<string>Distinct(stringcollectionName,stringFieldName,IMongoQueryquery=null) { MongoCollectioncol=GetDatabaseByType(_defaultDatabaseName).GetCollection(collectionName); varDistinctResult=col.Distinct(FieldName,query); varresult=newList<string>(); foreach(BsonValueiteminDistinctResult) { result.Add(item.AsString); } returnresult; }

使用Javascript进行聚合操作

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

///<summary> ///GroupByCount ///</summary> ///<paramname="collectionName"></param> ///<paramname="FieldName"></param> ///<returns></returns> publicstaticDictionary<string,int>GroupCount(stringcollectionName,stringFieldName,IMongoQueryquery=null) { MongoCollectioncol=GetDatabaseByType(_defaultDatabaseName).GetCollection(collectionName); GroupArgsg=newGroupArgs(); vargroupdoc=newGroupByDocument(); groupdoc.Add(FieldName,true); g.KeyFields=groupdoc; g.ReduceFunction=newBsonJavaScript("function(obj,prev){prev.count++;}"); g.Initial=newBsonDocument().Add("count",0); if(query!=null) { g.Query=query; } varGroupResult=col.Group(g); varresult=newDictionary<string,int>(); foreach(BsonDocumentiteminGroupResult) { result.Add(item.GetElement(FieldName).Value.ToString(),(int)item.GetElement("count").Value.AsDouble); } returnresult; }

TTL索引

使用MongoDB的TTL(TimeToLive)索引,可以实现定时缓存功能,数据经过指定时间后就自动从数据库里面删除。

很多缓存数据现在就是用TTL索引实现15分钟自动清除操作的。 ///<summary> ///设定数据缓存时间(以创建时间为基础) ///</summary> ///<paramname="collectionName"></param> ///<paramname="ExpiresMinute"></param> ///<paramname="database"></param> publicstaticvoidSetCacheTime(stringcollectionName,intExpiresMinute,stringdatabase="") { if(string.IsNullOrEmpty(database))database=_defaultDatabaseName; MongoCollectioncol=GetDatabaseByType(database).GetCollection(collectionName); if(col.IndexExistsByName("Cache")) { col.DropIndexByName("Cache"); } varoption=newIndexOptionsBuilder(); option.SetTimeToLive(newTimeSpan(0,ExpiresMinute,0)); option.SetName("Cache"); varindexkeys=newIndexKeysBuilder(); indexkeys.Ascending(newstring[]{nameof(EntityBase.CreateDateTime)}); col.CreateIndex(indexkeys,option); }

本文内容总结:MongoDB简介,MongoDB的管理工具,C#驱动程序的再包装,MongoDB的序列化设定(干货),FileStorage,全文检索,内置的聚合操作,使用Javascript进行聚合操作,TTL索引,

原文链接:https://www.cnblogs.com/TextEditor/p/5454168.html