霍元甲网盘下载周杰伦:,通过 MongoDB 推动 NoSQL(第3部分)

来源:百度文库 编辑:九乡新闻网 时间:2024/05/05 07:50:28
 

上一次,我使用探索测试继续对 MongoDB 进行探讨。我介绍了如何在测试期间启动和停止服务器,然后介绍了如何获取跨文档引用,并探讨了导致如此麻烦举动的原因。现在我们需要探索更多中间的 MongoDB 功能:谓词查询、聚合函数以及 MongoDB.Linq 程序集提供的 LINQ 支持。我还将提供一些有关在生产环境中安置 MongoDB 的注意事项。

当我们最终离开我们的主角 .. .

在相关的代码包中,我充实了探索测试的内容,使用我最喜欢的电视节目里的人物,加入了一组已存在的示例数据集以供处理。图 1 显示了之前的探索测试,已经过刷新器处理。到目前为止一切顺利。

图 1 示例探索测试

 

[TestMethod]public void StoreAndCountFamilyWithOid(){var oidGen = new OidGenerator();var peter = new Document();peter["firstname"] = "Peter";peter["lastname"] = "Griffin";peter["_id"] = oidGen.Generate();var lois = new Document();lois["firstname"] = "Lois";lois["lastname"] = "Griffin";lois["_id"] = oidGen.Generate();peter["spouse"] = lois["_id"];lois["spouse"] = peter["_id"];var cast = new[] { peter, lois };var fg = db["exploretests"]["familyguy"];fg.Insert(cast);Assert.AreEqual(peter["spouse"], lois["_id"]);Assert.AreEqual(fg.FindOne(new Document().Append("_id",peter["spouse"])).ToString(), lois.ToString());Assert.AreEqual(2,fg.Count(new Document().Append("lastname", "Griffin")));}

 

呼叫所有老人 .. .

在前面的文章中,客户端代码已经获得所有匹配特定标准的文档(例如“lastname”字段匹配特定的 String 或“_id”字段匹配特定的 Oid),但我还没有介绍如何进行谓词查询(例如“找到所有‘age’字段的值大于 18 的文档”)。事实上,MongoDB 并不使用 SQL 风格的接口来描述要执行的查询,而是使用 ECMAScript/JavaScript,而且它能接受要在服务器上执行的代码块以筛选或聚合数据,几乎就像存储过程一样。

这提供了一些类似 LINQ 的功能,甚至不用了解 Mongo.Linq 程序集支持的 LINQ 功能我们就能看出来。通过指定包含名为“$where”的字段的文档和描述要执行的 ECMAScript 代码的代码片段,可以随意创建复杂的查询:

 

[TestMethod]public void Where(){ICursor oldFolks =db["exploretests"]["familyguy"].Find(new Document().Append("$where",new Code("this.gender === 'F'")));bool found = false;foreach (var d in oldFolks.Documents)found = true;Assert.IsTrue(found, "Found people");}

 

正如您所看到的,Find 调用返回 ICursor 实例,尽管该实例本身不是 IEnumerable(表示它无法用在 ForEach 循环中),却包含一个类型为 IEnumerable 的 Documents 属性。如果查询会返回很大的数据集,通过将其 Limit 属性设置为 n,可以要求 ICursor 返回前 n 个结果。

谓词查询的语法共有四种格式,如图 2 所示。

图 2 四种不同的谓词查询语法

 

[TestMethod]public void PredicateQuery(){ICursor oldFolks =db["exploretests"]["familyguy"].Find(new Document().Append("age",new Document().Append("$gt", 18)));Assert.AreEqual(6, CountDocuments(oldFolks));oldFolks =db["exploretests"]["familyguy"].Find(new Document().Append("$where",new Code("this.age > 18")));Assert.AreEqual(6, CountDocuments(oldFolks));oldFolks =db["exploretests"]["familyguy"].Find("this.age > 18");Assert.AreEqual(6, CountDocuments(oldFolks));oldFolks =db["exploretests"]["familyguy"].Find(new Document().Append("$where",new Code("function(x) { return this.age > 18; }")));Assert.AreEqual(6, CountDocuments(oldFolks));}

 

在第二种和第三种格式中,“this”指的是要查询的对象。

事实上,您可以使用文档传达查询或命令,以便从驱动程序向数据库发送任意命令(即 ECMAScript 代码)。例如,IMongoCollection 接口提供的 Count 方法就是对这段冗长代码的简便替代方式:

 

[TestMethod]public void CountGriffins(){var resultDoc = db["exploretests"].SendCommand(new Document().Append("count", "familyguy").Append("query",new Document().Append("lastname", "Griffin")));Assert.AreEqual(6, (double)resultDoc["n"]);}

 

这意味着 MongoDB 文档介绍的所有聚合操作(例如“distinct”或“group”)都可以通过同一种机制进行访问,虽然 MongoDB.Driver API 未将它们作为方法提供。

您可以通过“特殊名称”语法“$eval”将查询之外的任意命令发送到数据库,这样就可以对服务器执行任何合法的 ECMAScript 代码块,仍旧很像存储过程:

 

[TestMethod]public void UseDatabaseAsCalculator(){var resultDoc = db["exploretests"].SendCommand(new Document().Append("$eval",new CodeWScope {Value = "function() { return 3 + 3; }",Scope = new Document() }));TestContext.WriteLine("eval returned {0}", resultDoc.ToString());Assert.AreEqual(6, (double)resultDoc["retval"]);}

 

或者直接对数据库使用所提供的 Eval 函数。如果这还不够灵活,MongoDB 允许在特殊的数据库集合“system.js”中添加 ECMAScript 函数,从而在数据库实例上存储用户定义的要在查询时执行的 ECMAScript 函数以及服务器端执行块,如 MongoDB 网站所述。

缺少的 LINQ

C# MongoDB 驱动程序也有 LINQ 支持,允许开发人员编写如图 3 所示的 MongoDB 客户端代码。

图 3 LINQ 支持示例

 

[TestMethod]public void LINQQuery(){var fg = db["exploretests"]["familyguy"];var results =from d in fg.Linq()where ((string)d["lastname"]) == "Brown"select d;bool found = false;foreach (var d in results){found = true;TestContext.WriteLine("Found {0}", d);}Assert.IsTrue(found, "No Browns found?");}

 

而且为了保持 MongoDB 数据库的动态特征,此示例不需要生成代码,只需调用 Linq 以返回可以“启用”MongoDB LINQ 提供程序的对象即可。在我撰写本文时,LINQ 支持还相当粗略,但在本文发表时,它将得到极大改进。新功能的文档和相关示例将在项目网站的 wiki 栏目发布。

发布是一项功能

最重要的是,如果要将 MongoDB 用在生产环境中,对于那些要让生产服务器和服务保持运行的工作人员来说,还有几个问题需要解决,这样才能减轻他们的工作负担。

首先,需要将服务器进程 (mongod.exe) 安装为服务,因为在生产服务器上一般不允许在交互式桌面会话中运行该进程。因此,mongod.exe 支持一个服务安装选项“--install”,通过该选项可将其安装为服务,然后通过服务面板或命令行“net start MongoDB”启动。但是,截止本文撰写时,--install 命令存在一个小问题:它通过查看执行安装所用的命令行来推断可执行文件的路径,因此必须在命令行中指定完整路径。也就是说,如果 MongoDB 安装在 C:\Prg\mongodb 中,您必须在命令提示符处(使用管理员权限)使用命令 C:\Prg\mongodb\bin\mongod.exe --install 将其安装为服务。

但是,所有的命令行参数,例如“--dbpath”,必须也显示在该安装命令中,这意味着如果端口、数据文件的路径等等设置发生更改,则必须重新安装服务。幸运的是,MongoDB 支持一个配置文件选项(通过“--config”命令行选项指定),因此通常最好的做法是将配置文件的完整路径传递到服务安装命令,然后在文件中进行其他所有配置:

 

C:\Prg\mongodb\bin\mongod.exe --config C:\Prg\mongodb\bin\mongo.cfg --installnet start MongoDB

 

像往常一样,测试服务是否成功运行的最简便方法就是使用 MongoDB 下载随附的 mongo.exe 客户端来连接服务。由于服务器通过套接字与客户端通信,因此您需要在防火墙中设置通道,以便允许与服务器的通信。

没有您需要的数据机器人

当然,对 MongoDB 服务器的不安全访问不可能是什么好事,因此阻止不需要的访问者访问服务器成为一项重要功能。MongoDB 支持身份验证,但是它的安全系统不像 SQL Server 这样的“大块头”数据库那么精密。

一般来说,第一步是使用 mongo.exe 客户端连接数据库并将管理员用户添加到管理数据库中(该数据库中包含用于运行和管理整个 MongoDB 服务器的数据),从而创建数据库管理登录,如下所示:

 

> use admin> db.addUser("dba", "dbapassword")

 

完成之后,所有进一步的操作(甚至是该外壳程序中的操作)都需要经过身份验证,通过在该外壳程序中进行显式身份验证完成:

 

> db.authenticate("dba", "dbapassword")

 

DBA 现在可以更改数据库并使用前面所示的同一个 addUser 调用来添加用户,从而将用户添加到 MongoDB 数据库中:

 

> use mydatabase> db.addUser("billg", "password")

 

通过 Mongo.Driver 连接数据库时,身份验证信息将作为用于创建 Mongo 对象的连接字符串的一部分进行传递,相同的身份验证过程将透明地进行:

 

var mongo = new Mongo("Username=billg;Password=password");

 

很自然,密码不应该直接硬编码在代码中或公开存储,而应该使用与所有基于数据库的应用程序相同的密码规则。实际上,整个配置(主机、端口、密码等)应该保存在配置文件中并通过 ConfigurationManager 类进行检索。

扩展到另一些代码

管理员应该定期查看正在运行的实例,以获得正在运行的服务器的相关诊断信息。MongoDB 支持一个 HTTP 接口用于与数据库交互,该接口运行的端口号比用于普通客户端通信的端口号高 1,000。MongoDB 的默认端口是 27017,因此该 HTTP 接口位于端口 28017,如图 4 所示。

图 4 用于与 MongoDB 交互的 HTTP 接口

该 HTTP 接口还允许更加偏向 REST 风格的通信方法,与 MongoDB.Driver 和 MongoDB.Linq 中的本机驱动程序正相反;MongoDB 网站对此有详细介绍,但用于访问集合内容的 HTTP URL 中需要添加数据库名称和集合名称(用斜线分隔),如图 5 所示。

图 5 用于访问集合内容的 HTTP URL

有关使用 WCF 创建 REST 客户端的详细信息,请参见 MSDN 文章“REST in Windows Communication Foundation (WCF)”。

专家的忠告

MongoDB 是一款发展迅速的产品,这些旨在探索 MongoDB 核心功能的文章有很多内容并未涉猎。尽管 MongoDB 不能直接替代 SQL Server,但在传统的关系数据库管理系统作用有限的领域,它确实是一种可行的存储替代方案。与 MongoDB 相同,mongodb-csharp 项目也处在蓬勃发展之中。撰写本文时,很多新的改进功能已经添加到 Beta 版中,包括使用普通对象处理强类型化的集合以及对 LINQ 支持的重大改进。请密切注意这两个项目。

但现在我们也应该和 MongoDB 说再见了。让我们把注意力转向孜孜不倦的程序员可能不熟悉(也应该存在争议)的其他开发人员领域。但在目前,愉快编程,并记住伟大的开发专家曾说过的“开发人员使用源代码获取知识,进行防御,切勿成为黑客”。

下载示例代码

关于作者:

Ted Neward 是 Neward & Associates 的负责人,这是一家专门研究 .NET Framework 企业系统和 Java 平台系统的独立公司。他曾写作 100 多篇文章,是 C# 领域最优秀的专家之一并且是 INETA 发言人,著作或合著过十几本书,包括即将出版的《Professional F# 2.0》(Wrox)。他定期担任顾问和导师,请通过 ted@tedneward.com 与他联系,或通过 blogs.tedneward.com 访问其博客。

原文链接:http://msdn.microsoft.com/zh-cn/magazine/ff798277.aspx

通过 MongoDB 使用 NoSQL(第1部分)

通过 MongoDB 推动 NoSQL(第2部分)