首先要有一些定义后的CSS文件,本例是用Bootstrap作为前端框架,可以从http://bootswatch.com/网站上下载一些主题文件,也就是一些定义好的Bootstap.css的文件。

然后将这些文件放到网站中Content文件夹Themes 下,目录组织结构如图:

二、然后在网站根目录新建一个文件夹为Helper,在下面建立一个Bootstrap.cs文件。

public class Bootstrap
{
public const string BundleBase = "~/Content/css";

//类作为一个类的成员。
public class Theme
{
public const string Cerulean = "Cerulean";
public const string Darkly = "Darkly";
public const string Flatly = "Flatly";
public const string Spacelab = "Spacelab";
public const string Stock = "Stock";
public const string Superhero = "Superhero";
}

public static HashSet<string> Themes = new HashSet<string>
{
Theme.Cerulean,
Theme.Darkly,
Theme.Flatly,
Theme.Spacelab,
Theme.Stock,
Theme.Superhero
};

public static string Bundle(string themename)
{
return BundleBase + themename;
}
}
}

三、打开app-start文件夹下BundleConfig文件,修改如下:将每个主题都捆绑

foreach (var theme in Bootstrap.Themes)
{
var stylePath=string.Format("~/Content/Themes/{0}/bootstrap.css",theme);
bundles.Add(new StyleBundle(Bootstrap.Bundle(theme)).Include( //创建捆绑 ,"~/Content/css+themename"
stylePath,
"~/Content/site.css"));

第一种方案

以下是多选一操作,假使把主题名字存放在Application 应用程序全局变量中。

四、要更改主题,可以把主题的名字字符串放在session 当中,也可以放在数据库中。都有缺点。session["ThemeName"]易丢失,跟客户端浏览器有关,如果存放在数据库中,可以与用户相关联。但我们这里的需求是通过后台更改前台的显示样式,所有可以把主题的名字字符串放在Application 或cache当中,这是应用程序全局共享的。

打开全局应用程序配置文件Global.asax.cs,

public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);

Application["CssTheme"] = Bootstrap.Theme.Stock; //增加应用程序状态集合。
}
}

五、更改布局页_Layout 。因为如果布局页引入了主题样式文件,更改了布局页,全站的样式都更改了。

@using MajorConstruction.Helpers;
@{
var theme = System.Web.HttpContext.Current.Application["CssTheme"] as string ?? Bootstrap.Theme.Stock; //当前请求上下文的应用程序状态。  //通过应用程序上下文对象的当前请求调用 Application对象。??为空值合并运算符,如果为空,就为默认的Stock 主题。
}

@Styles.Render(Bootstrap.Bundle(theme))
@Scripts.Render("~/bundles/modernizr")

六、更改主题了。定义一个ThemeContoller的控制器。get返回View,Post执行更改。

public class ThemeController : Controller
{
// GET: Admin/Theme
public ActionResult ChangeTheme()
{

return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ChangeTheme(string theme)
{
HttpContext.Application["CssTheme"] = theme;
return View();
}

七、定义 更改视图,显示出全部的主题,供选择。因为这个页面只需要提交一个主题名字字符串到控制器就可以了,所有我们使用了一个表单里面有一个隐藏字段,通过AJax的方式提交。

@using MajorConstruction.Helpers;

@{
ViewBag.Title = "更改主题";
}

<h2>@ViewBag.Title</h2>
<hr />
<div class="container">
<div class="row">
@foreach (var theme in Bootstrap.Themes)
{
<div class="col-md-3">
<div class="panel panel-default">  //使用Bootstrap的面板 ,不要标题。因为只是为了加一个边框,所以只使用了panel-body
<div class="panel-body">
<h2>@theme</h2>
<br />
<br />
<p>
@{
bool IsCurrent = theme == HttpContext.Current.Application["CssTheme"].ToString();   //判定当前遍历的主题是不是正在使用的,如果是正在使用的,更改按钮就变灰。把主题绑定在链接的上JavaScript函数
string btnDisabled = IsCurrent ? "disabled" : null;
}

//下面是一个按钮形式的链接,执行Javascript脚本 ,绑定主题名字值。主题名字必须加引号。不然,会提示 Uncaught ReferenceError: XX 未定义 is not defined.
<a class="btn btn-success @btnDisabled" href="javascript:SetActive('@theme')">应用主题</a> <!--把主题绑定在JavaScript函数上,通过调用Javascript函数提交隐藏表彰。-->
<!--还需要特别注意,调用 javascript 函数的参数@theme必须加引号,如果不加引号,总是谷哥浏览器总是提示 Uncaught ReferenceError: XX 未定义 is not defined,因为@theme变量本来就不是值类型,而是HashSet类型-->

以前就是没加引号,搞了半天,都提交不起,什么方法都试过了,还以为是服务端代码有问题。
</p>
</div>

</div>
</div>
}

</div>
</div>

@using (Html.BeginForm("ChangeTheme", "Theme", FormMethod.Post, new { id = "themeForm" }))
{
@Html.AntiForgeryToken()
<input type="hidden" name="theme" id="themeInput" />
}

@section Scripts {
@Scripts.Render("~/bundles/jqueryval")

<script type="text/javascript">
var changeThemeUrl = '@Url.Action("ChangeTheme")';

function SetActive(themename) {
$("#themeInput").val(themename); //将参数值传递给隐藏表单。

$("#themeForm").submit(); //提交表单,将 theme=themename 发送至控制器POST 方法中。

}

</script>

大功告成。
 
第二种方案。也可以把主题的名字放在数据库当中。也就是从第四步重新开始。
四、建立模型,在Model文件夹下建立一个BootstrapTheme.cs文件。

namespace MajorConstruction.Models
{
public class BootstrapTheme
{
[Display(Name="主题ID")]
public string BootstrapThemeID { get; set; }

[Display(Name="主题名称")]
[Required(AllowEmptyStrings=false)]
[StringLength(50,ErrorMessage="{0}不能超过50个字符")]
public string ThemeName { get; set; }

[Display(Name="主题描述")]
[StringLength(50,ErrorMessage="{0}不能超过50个字符")]
public string ThemeDescription { get; set; }

[Display(Name ="是否当前主题")]
public bool? IsActived { get; set; }

public BootstrapTheme()
{
this.BootstrapThemeID = Guid.NewGuid().ToString();
}

}
}

五、将BootstrapTheme 类加入到数据库上下文当中。可以设置一个数据库上下文的DbContext 的静态构造函数和初始化类,用于在数据库生成初始值。静态构造方法调用这个初始化类。

1、加入到DbContext 中。

namespace MajorConstruction.Models
{
public class MajorContext:DbContext
{
public DbSet<Category> Categories { get; set; }

public DbSet<Article> Articles { get; set; }

public DbSet<Course> Courses { get; set; }

public DbSet<Resource> Resources { get; set; }

public DbSet<BootstrapTheme> BootstrapThemes { get; set; }

public MajorContext()
: base("MajorContext")
{ }

//静态构造函数。MSDN:静态构造函数用于初始化任何静态数据,或用于执行仅需执行一次的特定操作。在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数  。使用静态构造函数感觉要比 在config 配置文件里修改<EntityFramework>节点下增加<contexts><contexts>来得方便。或者在gloabe.asax 下设置初始化类来得方便。

<entityFramework>
<contexts>
<context type="ContosoUniversity.DAL.SchoolContext, ContosoUniversity">
<databaseInitializer type="ContosoUniversity.DAL.SchoolInitializer, ContosoUniversity" />
</context>
</contexts>

2、设置静态构造函数
static MajorContext()
{
//设置数据库初始化器,它就在应用程序运行的时候加载。
Database.SetInitializer<MajorContext>(new MajorContextInitializer());
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}

}
}

3、在Model 文件下新建一个初始化为类,MajorContextInitializer。

namespace MajorConstruction.Models
{
public class MajorContextInitializer:DropCreateDatabaseIfModelChanges<MajorContext>
{
protected override void Seed(MajorContext context)
{
var themeList = new List<BootstrapTheme>()
{
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Stock" ,ThemeDescription="默认主题。黑色背景导航条,蓝色背景标题", IsActived=true},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Cerulean" ,ThemeDescription="深蓝色背景导航条,浅蓝色背景标题", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Cosmo" ,ThemeDescription="天蓝色背景导航条,天蓝色背景标题", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Darkly" ,ThemeDescription="翠绿色背景导航条,蓝黑色背景标题,黑色背景", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Flatly" ,ThemeDescription="翠绿色背景导航条,蓝黑色背景标题", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Sandstone" ,ThemeDescription="绿色背景导航条,蓝黑色背景标题", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Spacelab" ,ThemeDescription="深蓝色背景导航条,深蓝色背景标题", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Superhero" ,ThemeDescription="橘黄色背景导航条,橘黄色背景标题,小号字", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="United" ,ThemeDescription="朱红色背景导航条,橘黄色背景标题", IsActived=false},
new BootstrapTheme { BootstrapThemeID=Guid.NewGuid().ToString(), ThemeName="Yeti" ,ThemeDescription="蓝色背景导航条,蓝色背景标题,小号字", IsActived=false}
};

foreach (var theme in themeList)
{
var _theme = context.BootstrapThemes.Where(x => x.ThemeName == theme.ThemeName).FirstOrDefault();
if (_theme == null)
{
context.BootstrapThemes.Add(theme);

}

}
context.SaveChanges();
base.Seed(context);
}
}
}

六、执行更改主题的操作。

控制器:

[Authorize(Roles = "SuperAdmin,Teacher")]
public class ThemeController : Controller
{
/*
private List<BootstrapViewModel> themeList = new List<BootstrapViewModel>()
{
new BootstrapViewModel { ThemeName="Stock" ,ThemeDescription="默认主题。黑色背景导航条,蓝色背景标题"},
new BootstrapViewModel { ThemeName="Cerulean" ,ThemeDescription="深蓝色背景导航条,浅蓝色背景标题"},
new BootstrapViewModel { ThemeName="Cosmo" ,ThemeDescription="天蓝色背景导航条,天蓝色背景标题"},
new BootstrapViewModel { ThemeName="Darkly" ,ThemeDescription="翠绿色背景导航条,蓝黑色背景标题,黑色背景"},
new BootstrapViewModel { ThemeName="Flatly" ,ThemeDescription="翠绿色背景导航条,蓝黑色背景标题"},
new BootstrapViewModel { ThemeName="Sandstone" ,ThemeDescription="绿色背景导航条,蓝黑色背景标题"},
new BootstrapViewModel { ThemeName="Spacelab" ,ThemeDescription="深蓝色背景导航条,深蓝色背景标题"},
new BootstrapViewModel { ThemeName="Superhero" ,ThemeDescription="橘黄色背景导航条,橘黄色背景标题,小号字"},
new BootstrapViewModel { ThemeName="United" ,ThemeDescription="朱红色背景导航条,橘黄色背景标题"},
new BootstrapViewModel { ThemeName="Yeti" ,ThemeDescription="蓝色背景导航条,蓝色背景标题,小号字"}
};
*/

private BootstrapThemeService _bootstrapThemeService = new BootstrapThemeService(ContextFactory.GetCurrentContext());  //使用库模式,
// GET: Admin/Theme
public async Task<ActionResult> ChangeTheme()
{
var themeList = await _bootstrapThemeService.FindAll().OrderBy(c => c.ThemeName).ToListAsync(); //是使用异步方法,必须引入System.Data.Entity 和 System.Threading.Tasks 命名空间。
return View(themeList);
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ChangeTheme(string theme)
{
//HttpContext.Application["CssTheme"] = theme;
if (!string.IsNullOrEmpty(theme)) //找来好久错误,没想到是这个判断错了,少了一个"!"号。应该是如果此字符串非空,就来将该主题设为 选中状态。其他主题设为非选中状态。设置断点调试才发现此问题。
{
foreach (var item in await _bootstrapThemeService.FindAll().ToListAsync())
{
if (item.ThemeName == theme)
{
item.IsActived = true;
}
else
{
item.IsActived = false;

}
_bootstrapThemeService.Update(item);

}
}
//return View(themeList);
return View(await _bootstrapThemeService.FindAll().OrderBy(c =>c.ThemeName).ToListAsync());
}

public async Task<ActionResult> DefaultTheme()  //设置默认主题。
{

// HttpContext.Application["CssTheme"] = "Stock";
// return View("ChangeTheme", themeList);
foreach (var item in await _bootstrapThemeService.FindAll().ToListAsync())
{
if (item.ThemeName == "Stock")
{
item.IsActived = true;
}
item.IsActived = false;
_bootstrapThemeService.Update(item);
}

return View("ChangeTheme",await _bootstrapThemeService.FindAll().OrderBy(c =>c.ThemeName).ToListAsync());

}
}
}

视图:跟前面第一种方案差不多,主要在页面中建立一个隐藏表单,利用ajax 的方式调用 控制器的方法。

@using MajorConstruction.Helpers;
@model IEnumerable<MajorConstruction.Models.BootstrapTheme>
@{
ViewBag.Title = "更改主题";
}

<h2>@ViewBag.Title</h2>
<hr />
<div class="container">
<div class="row">
@foreach (var theme in Model)
{
<div class="col-md-3">
<div class="panel panel-default">
<div class="panel-body">
<h2>@theme.ThemeName</h2>
<p class="lead">
@theme.ThemeDescription
</p>
<p>
@{
// bool IsCurrent = @theme.ThemeName == HttpContext.Current.Application["CssTheme"].ToString();
//string btnDisabled = IsCurrent ? "disabled" : null;

string btnDisabled = theme.IsActived == true ? "disabled" : null;
}
<a class="btn btn-primary @btnDisabled" href="javascript:SetActive('@theme.ThemeName')">应用主题</a> <!--把主题绑定在JavaScript函数上,通过调用Javascript函数提交隐藏表彰。-->
<!--还需要特别注意,调用 javascript 函数的参数@theme必须加引号,如果不加引号,总是谷哥浏览器总是提示 Uncaught ReferenceError: XX 未定义 is not defined,因为@theme变量本来就不是值类型,而是HashSet类型-->
</p>
</div>

</div>
</div>
}

</div>
</div>

@using (Html.BeginForm("ChangeTheme", "Theme", FormMethod.Post, new { id = "themeForm" }))
{
@Html.AntiForgeryToken()
<input type="hidden" name="theme" id="themeInput" />
}

@section Scripts {
@Scripts.Render("~/bundles/jqueryval")

<script type="text/javascript">
var changeThemeUrl = '@Url.Action("ChangeTheme")';

function SetActive(themename) {
$("#themeInput").val(themename); //将参数值传递给隐藏表单。

$("#themeForm").submit(); //提交表单,将 theme=themename 发送至控制器POST 方法中。

}

</script>

}

七、更改前台页面的布局页_Layout页。

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - 省级重点专业</title>
@using MajorConstruction.Helpers;
@{
//var theme = System.Web.HttpContext.Current.Application["CssTheme"] as string ?? Bootstrap.Theme.Stock; //当前请求上下文的应用程序状态。 将Theme值保存在全局应用程序变量Application中按理说不应该过期,但是事实上挂在IIS上时会过期,一段时间后,就会恢复默认值。还不如直接保存在数据库中。
var theme = Bootstrap.Theme.Stock;
if (ViewBag.ActiveTheme != null)  //   ViewBag.ActiveTheme 对象 表示从控制器操作方法传过来的当前选中的主题。但是为每个方法或每个控制器都返回一个ViewBag对象,一个一个的设置麻烦。所以下面使用了操作过滤器。
{
theme = ViewBag.ActiveTheme;
}
}

@Styles.Render(Bootstrap.Bundle(theme))
@Scripts.Render("~/bundles/modernizr")

</head>

八、使用操作过滤器返回ViewBag.ActiveTheme 对象。

在网站根目录下建立一个Filters 文件夹,新建一个ThemeFilter 的cs文件,继承自ActionFilterAttribute 类。覆写OnActionExecuted方法。

namespace MajorConstruction.Filters
{
public class ThemeFilter:ActionFilterAttribute //操作过滤器属性需要引用 System.Web.Mvc 命名空间;
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
string ActiveThemeName = "Stock";
var _BootstrapThemeService = new BootstrapThemeService(ContextFactory.GetCurrentContext());
var activeTheme = _BootstrapThemeService.FindAll().Where(x =>x.IsActived == true).FirstOrDefault();
if (activeTheme != null)
{
ActiveThemeName = activeTheme.ThemeName;

}

filterContext.Controller.ViewBag.ActiveTheme = ActiveThemeName;   //该 过滤上下文的 控制器都返回一个ViewBag.ActiveTheme 对象,它的值是目前选中的主题的名字。
base.OnActionExecuted(filterContext);
}
}
}

九:将使用该布局页的控制器的加上 [ThemeFilter] 的数据注解。那么该控制器的所有操作方法都将返回一个ViewBag.ActiveTheme 对象,并用它的值是目前选中的主题的名字。

[ThemeFilter]
public class HomeController : Controller
{
private CategoryService _categoryService = new CategoryService(ContextFactory.GetCurrentContext());
private ArticleService _articleService = new ArticleService(ContextFactory.GetCurrentContext());
private CourseServie _courseService = new CourseServie(ContextFactory.GetCurrentContext());
private ResourceService _resourceService = new ResourceService(ContextFactory.GetCurrentContext());
private MajorContext db =new MajorContext();
public ActionResult Index()

当然,也可以设置全局应用程序过滤器。打开根目录下的App_Start 文件夹下的FilterConfig.cs 文件。

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new ThemeFilter()); //全局应用程序过滤器,程序中所有控制器的所有方法都将执行这个过滤操作。
}

这样,就将主题数据持久化的保存在了数据库中,应用程序重新启动,或者是过一段时间,都会保存以前的主题。

截图如下:

asp.net MVC 切换网站主题的更多相关文章

  1. ASP.NET MVC 3 网站优化总结(三)Specify Vary: Accept-Encoding header

    继续进行 ASP.NET MVC 3 网站优化工作,使用 Google Page 检测发现提示 You should Specify Vary: Accept-Encoding header,The ...

  2. ASP.NET MVC 3 网站优化总结(一) 使用 Gzip 压缩

    网站开启 Gzip 压缩的好处相信很多人都已经清楚,这样做可以提高网站的性能.那么为什么很多网站没有开启 Gzip 压缩功能呢?原因有4点:防病毒软件.浏览器 bug.网站代理和服务器未配置. 使用 ...

  3. ASP.NET MVC 3 网站优化总结(六)压缩 HTML

    压缩 html 可以去除代码中无用的空格等,这样可提高网站的加载速度并节省带宽.今天就让我们看看在 ASP.NET MVC 3 怎么实现 html 压缩,我们可通过实现 ActionFilter 来完 ...

  4. Asp.NET MVC 拍卖网站,拆解【1】预览与目录

    本人最近带创业团队基本做完了一个艺术品拍卖的外包项目,分为网站前台(asp.net mvc5),网站管理员管理的后台使用的9900端口(asp.net mvc5),监听拍卖状态的windows服务,为 ...

  5. Asp.NET MVC 拍卖网站,拆解【2】 Asp.NET MVC章回,第(1)节

    时间和篇幅所限,MVC不会介绍基本的建站过程,请参照博客园技术专题文章传送门  英语足够好的请直接去微asp.net 官网 传送门(强烈推荐,尤其是想使用最新技术的时候更应该直接去官网),本文主要介绍 ...

  6. ASP.NET MVC实现网站验证码功能

    网站添加验证码,主要为防止机器人程序批量注册,或对特定的注册用户用特定程序暴力破解方式,以进行不断的登录.灌水等危害网站的操作.验证码被广泛应用在注册.登录.留言等提交信息到服务器端处理的页面中. 在 ...

  7. ASP.NET MVC - 发布网站

    原文地址:http://www.w3school.com.cn/aspnet/mvc_publish.asp 学习如何在不使用 Visual Web Developer 的情况下发布 MVC 应用程序 ...

  8. 响应式Asp.net MVC企业网站源码

    最近时间充裕,自己写了一个响应式MVC企业网站系统,用于回顾自己的MVC知识.网站源码后台和前台都采用响应式布局,可以适应不同的屏幕. 一.源码描述 响应式企业网站系统,前台和后台都采用了响应式布局, ...

  9. .net core Asp.net Mvc Ef 网站搭建 vs2017 1)

    1)开发环境搭建 首先下载安装vs2017  地址 :https://www.visualstudio.com/zh-hans/downloads/ 安装勾选几项如下图 ,注意点在单个组件时.net ...

随机推荐

  1. bzoj3875 【Ahoi2014】骑士游戏 spfa处理后效性动规

    骑士游戏 [故事背景] 长期的宅男生活中,JYY又挖掘出了一款RPG游戏.在这个游戏中JYY会 扮演一个英勇的骑士,用他手中的长剑去杀死入侵村庄的怪兽. [问题描述] 在这个游戏中,JYY一共有两种攻 ...

  2. Codeforces936D. World of Tank

    $n \leq 1e9$,$n*2$的网格里有$m_1+m_2 \leq 1e6$个障碍物,现有一坦克从$(0,1)$出发要到$(n+1,1/2)$,他每秒可以换行(纵坐标1变2或2变1)也可以发炮弹 ...

  3. ZOJ 3471 【状态压缩DP】

    题意: 有n种化学物质,他们彼此反应会有一种消失并释放出能量. 给出矩阵,第i行j列代表i和j反应j消失释放的能量. 求最大释放多少能量. 思路: 状态压缩DP,我是这么想的. 利用二进制0代表该物质 ...

  4. 学习日常笔记<day16>mysql加强

    1.数据约束 1.1什么是数据约束 对用户操作表的数据进行约束 1.2 默认值 作用:当永辉对使用默认值的字段不插入值的时候,就使用默认值 注意: 1)对默认值字段插入null是可以的 2)对默认值字 ...

  5. eclipse设置每次提交代码忽略target、.settings、.svn、.project文件

  6. maven的超级pom

    对于 Maven3,超级 POM 在文件 %MAVEN_HOME%/lib/maven-model-builder-x.x.x.jar 中的 org/apache/maven/model/pom-4. ...

  7. 【转载】同步和互斥的POSIX支持(互斥锁,条件变量,自旋锁)

    上篇文章也蛮好,线程同步之条件变量与互斥锁的结合: http://www.cnblogs.com/charlesblc/p/6143397.html   现在有这篇文章: http://blog.cs ...

  8. CentOS 6.x DRBD

    CentOS 6.x DRBD 一.drbd概述     Distributed Replicated Block Device(DRBD)是一种基于软件的,无共享,复制的存储解决方案,在服务器之间的 ...

  9. Linux学习笔记总结

    零.求人不如求已:        1. 在Linux中,文件,目录,驱动,命令,脚本都视为文件,也即一切皆file. 2.记住使用Linux 的关键就是六个字: 命令.选项.參数. 3.学会看帮助,不 ...

  10. 【Mongodb教程 第十一课 】MongoDB 聚合

    聚合操作过程中的数据记录和计算结果返回.聚合操作分组值从多个文档,并可以执行各种操作,分组数据返回单个结果.在SQL COUNT(*)和group by 相当于MongoDB的聚集. aggregat ...