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在实际项目中的使用的更多相关文章

  1. MongoDB在实际项目

    MongoDB在实际项目中的使用   MongoDB简介 MongoDB是近些年来流行起来的NoSql的代表,和传统数据库最大的区别是支持文档型数据库.当然,现在的一些数据库通过自定义复合类型,可变长 ...

  2. 使用MongoDB在项目中实际运用

    一.MongoDB,一个数据库,我们怎么去使用它呢?我们首先了解一下什么是MongoDb 官网的介绍是:MongoDB是专为可扩展性,高性能和高可用性而设计的数据库.它可以从单服务器部署扩展到大型.复 ...

  3. .Net Core ORM选择之路,哪个才适合你 通用查询类封装之Mongodb篇 Snowflake(雪花算法)的JavaScript实现 【开发记录】如何在B/S项目中使用中国天气的实时天气功能 【开发记录】微信小游戏开发入门——俄罗斯方块

    .Net Core ORM选择之路,哪个才适合你   因为老板的一句话公司项目需要迁移到.Net Core ,但是以前同事用的ORM不支持.Net Core 开发过程也遇到了各种坑,插入条数多了也特别 ...

  4. NoSql非关系型数据库之MongoDB应用(三):MongoDB在项目中的初步应用

    业精于勤,荒于嬉:行成于思,毁于随. 我们可以结合相关的IDE做一个简单的增删改查了,实现MongoDB在项目中的初步应用. 前提是安装了MongoDB服务和MongoDB可视化工具,没有安装的可以点 ...

  5. Mongo基础使用,以及在Express项目中使用Mongoose

    MongoDB的基本使用 MongoDB特点: 使用BSON存储数据 支持相对丰富的查询操作(相对其他nosql数据库) 支持索引 副本集(支持多个实例/多个服务器运行同个数据库) 分片(数据库水平扩 ...

  6. 在WebStorm环境中给nodejs项目中添加packages

    照前文 http://www.cnblogs.com/wtang/articles/4133820.html  给电脑设置了WebStorm的IDE的nodejs开发环境.新建了个express的网站 ...

  7. 夺命雷公狗---node.js---19之项目的构建在node+express+mongo的博客项目4mongodb在项目中的基本引入

    首先我们在命令行下先建立这个库: 然后我们在项目中引入mongodb的模块: var MongoClient = require('mongodb').MongoClient; var DB_STR ...

  8. 在.NET项目中使用PostSharp,使用CacheManager实现多种缓存框架的处理

    在前面几篇随笔中,介绍了PostSharp的使用,以及整合MemoryCache,<在.NET项目中使用PostSharp,实现AOP面向切面编程处理>.<在.NET项目中使用Pos ...

  9. 使用反射+策略模式代替项目中大量的switch case判断

    我这里的业务场景是根据消息类型将离线消息存入mongoDB不同的collection中.其中就涉及到大量的分支判断,为了增强代码的可读性和可维护性,对之前的代码进行了重构. 先对比一下使用反射+策略模 ...

随机推荐

  1. Android获取View对应的Bitmap

    我的应用里面有一个需求,将一个画面分享出去,这个画面底层是一个View,所以首先要把这个View转换成Bitmap,然后在分享这个bitmap即可.话不多说,直接上代码. 有个地方需要注意一下:就是/ ...

  2. 12小时包你学会基于ReactMix框架的ReactNativeApp开发(一)Hello World!

    ReactMixhttps://github.com/xueduany/react-mix自从昨天发布起来,得到了不少小伙伴的热捧,很高兴帮助大家解决了憋在心中很久的问题“如果我只会HTML,Css, ...

  3. javascript无缝滚动示例

    效果 图片大小均为200*200; 默认向左循环滚动; 鼠标悬浮暂停,鼠标移走继续滚动; 可以在此基础进行扩展. 下面是代码: <!doctype html> <html lang= ...

  4. mongodb数据类型

    随着web2.0的时代到来,关系型数据库在越来越多的场景下暴漏出许多问题,为了解决这类问题,NoSql数据库应用而生,今天就来说说当下比较主流的NoSql数据库mongodb.   1. 基本数据类型 ...

  5. Atitit attilax总结的对于attilax重要的jsr规范,以及需要增加的jsr规范

    Atitit attilax总结的对于attilax重要的jsr规范,以及需要增加的jsr规范 需要增加的jsr规范1 开发常用的10个规范(jsp etc)1 other开发常用的50个规范1 需要 ...

  6. Atitit  rgb yuv  hsv HSL 模式和 HSV(HSB) 图像色彩空间的区别

    Atitit  rgb yuv  hsv HSL 模式和 HSV(HSB) 图像色彩空间的区别 1.1. 色彩的三要素 -- 色相.明度.纯度1 1.2. YUV三个字母中,其中"Y&quo ...

  7. fir.im Weekly - 进击的 Swift

    最近 Swift 开源了,众开发者们欢呼雀跃.感谢开源,这是最好的时代.本期 fir.im Weekly 准备了一些关于 Swift 的"新鲜"干货分享,也包括一些优秀的 GitH ...

  8. c#设计模式-观察者模式

    Observer 与 Subject 互为耦合,但是这种耦合的双方都依赖于抽象,而不依赖于具体. 一.观察者模式 目的 我们都知道解决一个问题有N种解决方式,但在面向对象的设计中如何能做到“高内聚,低 ...

  9. web 安全

    一.客户端脚本安全 (1)跨站脚本攻击(XSS): XSS攻击,通常指黑客通过“html注入” 篡改了网页,插入了恶意的脚本,从而在用户浏览网页的时候,控制用户浏览器的一种攻击. 最常见的XSS攻击就 ...

  10. Searching for a valid kernel header path... The path "" is not a valid path to the ***** kernel headers. Would you like to change it? [yes]

    在centos 6.5安装vmtools时候,解压包,mount挂载后,安装pl过程中报 这个问题,半天没有解决,google 后发现这样就行了 I installed the kernel-deve ...