日期:2014-05-16  浏览次数:20556 次

Pure JS (4.1): 使用 MongoDB 进行数据存储和管理
Pure JS (4.1): 使用 MongoDB 进行数据存储和管理


  MongoDB 的一大特性就是 “JavaScript Friendly”,“Scheme Free” 的主张天生就是与 JavaScript 的开发理念相契合的。
  它允许我们通过 eval 进行数据的初始化,以及在查询中使用 JS 对象作为查询条件,并且查询结果也可以很容易地转为 JS 对象或数组。

  最近三篇文章将重点介绍如何在服务器端用 JS 与 MongoDB 进行交互;
  我将这些操作封装在 pure.db 中,可能封装得并不完善,但可以很容易地进行修改和扩展 。

  第一篇文章通过测试案例来了解 pure.db 的用法;
  第二篇文章说明在实际的 Web 应用中如何使用它;
  第三篇文章探讨 pure.db 的实现细节。

运行测试案例

  首先,我们需要到这里下载 MongoDB:http://www.mongodb.org/downloads

  通过命令行运行 mongod 和 mongo(默认情况下需要先在根目录创建文件夹 \data\db )。
  mongod 是一个接受命令的守护进程,而 mongo 是一个与 mongod 交互的命令行 shell 工具。

  然后下载附件,这是一个 eclipse 工程(就是我们之前一直使用的 PureJS 工程),添加到eclipse中,运行 test/purejs/test/DBTest.java。(鼠标右键 -> Run As -> JUnit Test 或 Alt + Shift + X, T)

  正常情况下,应该看到像这样的绿条:



引用
  如果出现 Error 或 Failure,在确认不是环境问题(mongod 正常运行中,Java 7 和 Junit 4 的配置没有问题)之后,请通过留言或站内信等方式通知我。


  我们可以看到 DBTest 类的结构是这样的:
package purejs.test;

import org.junit.*;
import purejs.core.*;

public class DBTest {
	@Before
	public void setUp() throws Exception {
		JSEngine.excuteFile("scripts/config.js");
		JSEngine.excuteFile("scripts/lib/pure.js");
		JSEngine.excuteFile("scripts/test/db/before.js");
	}

	@Test
	public void list() throws Exception {
		execute("list");
	}

	@Test
	public void listWithLimit() throws Exception {
		execute("listWithLimit");
	}

	@Test
	public void listWithEquals() throws Exception {
		execute("listWithEquals");
	}

	// 其他类似的测试方法 ...

	private void execute(String name) throws Exception {
		JSEngine.excuteFile("scripts/test/db/" + name + ".js");
		JSEngine.invoke("run");
	}
}

  也就是说每个测试方法实际上就是运行一个 js 文件,我们打开文件夹 scripts/test/db ,所有用于测试的 js 文件都在这里,总共有 25 个测试文件以及一个初始化脚本 before.js ,接下来我们将选择其中的重点进行说明。

通过 eval 进行数据的初始化

  数据初始化的脚本 before.js 调用 pure.db.eval(func) 进行数据的初始化,传入一个函数,函数中的代码将直接在 MongoDB 运行,可以在这里查看原生的 MongoDB js 的写法:
  http://www.mongodb.org/display/DOCS/SQL+to+Mongo+Mapping+Chart

  before.js 首先建立了一个测试框架:
function run() {
	setUp();
	execute();
	verify();
	tearDown();
}

  然后实现了 setUp 函数和 tearDown 函数,而 execute 函数和 verify 函数则分别在每个测试文件中实现。

  【setUp】

  在 setUp 函数中,首先调用 tearDown 函数进行数据的清理,然后通过 eval 进行数据初始化,初始化的步骤包括:
  1. 获取 DB 中名为 'users' 的 collection
  2. 为 collection 创建索引,索引字段为 name ,排序方式为升序
  3. 在 users 中存放一组测试数据

  具体实现如下:
function setUp() {
	tearDown();

	pure.db.eval(function(){
		var users = db.users;
		users.ensureIndex({ name: 1 });

		users.insert({ name: 'user1', desc: 'desc1' });
		users.insert({ name: 'user2', desc: 'desc2' });
		users.insert({ name: 'user3', desc: 'desc3' });
		users.insert({ name: 'xxxxx', desc: 'desc3', age: 20 });
	});
}

  虽然 eval 很酷,但根据官方文档说明,运行 eval 时将阻塞所有的其他操作。
  因此,最好只在数据初始化、数据迁移等特殊应用场景使用它。
  所有测试的前提就是 eval 可用,因此没有针对 eval 的测试。

  另外,因为建立了索引,所以后续的测试中通常不会对记录进行排序;但最近被更新的数据将被放在最后,顺序也就被打乱了。因此在实际应用中,每次获取数据后还是要进行排序的。

  向 users 中插入的前三个对象很有规律,而第四个对象是为了测试 dintict,exists 等函数的用法而特意增加的。

  【tearDown】

  tearDown 首先将 context 清空,通过 eval -> db.users.drop 删除 users。
  实现如下:
function tearDown() {
	context = {};

	pure.db.eval(function(){
		db.users.drop();
	});
}

  context 对象用于在 excute 函数和 verify 函数之间传递数据,所以每次执行测试前后都需要重新进行初始化。