[转载]mongoDB 入门指南、示例 - hoojo - 博客园

mikel阅读(1069)

[转载]mongoDB 入门指南、示例 – hoojo – 博客园.

一、准备工作

1、 下载mongoDB

下载地址:http://www.mongodb.org/downloads

选择合适你的版本

相关文档:http://www.mongodb.org/display/DOCS/Tutorial

2、 安装mongoDB

A、 不解压模式:

将 下载下来的mongoDB-xxx.zip打开,找到bin目录,运行mongod.exe就可以启动服务,默认端口27017,db保存的路径是系统C 硬盘目录的根目录的/data/db目录。也就是说,如果你的mongoDB-xxx.zip在E盘,那么你需要在C盘下建立data/db目录。 mongoDB不会帮你建立这个目录的。

然后运行mongo即可连接到test数据库,你就可以进行数据操作。运行help显示帮助命令行。

B、 解压模式

将 下载下来的mongoDB-xxx.zip解压到任意目录,找到bin目录,运行mongod.exe就可以启动mongoDB,默认端口 27017,db保存的路径是当前zip所在硬盘目录的根目录的/data/db目录。也就是说,如果你的mongoDB-xxx.zip在E盘,那么你 需要在E盘下建立data/db目录。mongoDB不会帮你建立这个目录的。

然后运行mongo即可连接到test数据库,你就可以进行数据操作。运行help显示帮助命令行。

3、 简单测试

> 2+4
6
> db
test
> //第一次插入数据会创建数据库
Fri May 20 16:47:39 malformed UTF-8 character sequence at offset 27
error2:(shellhelp1) exec failed: malformed UTF-8 character sequence at offset 27
> db.foo.insert({id: 2011, userName: 'hoojo', age: 24, email: "hoojo_@126.com"});
> db.foo.find();
{ "_id" : ObjectId("4dd62b0352a70cbe79e04f81"), "id" : 2011, "userName" : "hoojo",
"age" : 24, "email" : "hoojo_@126.com" }
>

上面完成了简单运算,显示当前使用的数据库,以及添加数据、查询数据操作

 

二、DB shell数据操作

shell命令操作语法和JavaScript很类似,其实控制台底层的查询语句都是用JavaScript脚本完成操作的。

Ø 数据库


1、Help查看命令提示
help
db.help();
db.yourColl.help();
db.youColl.find().help();
rs.help();

2、切换/创建数据库
>use yourDB;
当创建一个集合(table)的时候会自动创建当前数据库

3、查询所有数据库
show dbs;

4、删除当前使用数据库
db.dropDatabase();

5、从指定主机上克隆数据库
db.cloneDatabase(“127.0.0.1”);
将指定机器上的数据库的数据克隆到当前数据库

6、从指定的机器上复制指定数据库数据到某个数据库
db.copyDatabase("mydb", "temp", "127.0.0.1");
将本机的mydb的数据复制到temp数据库中

7、修复当前数据库
db.repairDatabase();

8、查看当前使用的数据库
db.getName();
db;
db和getName方法是一样的效果,都可以查询当前使用的数据库

9、显示当前db状态
db.stats();

10、当前db版本
db.version();

11、查看当前db的链接机器地址
db.getMongo();

Ø Collection聚集集合


1、创建一个聚集集合(table
db.createCollection(“collName”, {size: 20, capped: 5, max: 100});

2、得到指定名称的聚集集合(table
db.getCollection("account");

3、得到当前db的所有聚集集合
db.getCollectionNames();

4、显示当前db所有聚集索引的状态
db.printCollectionStats();

Ø 用户相关

1、添加一个用户
db.addUser("name");
db.addUser("userName", "pwd123", true);
添加用户、设置密码、是否只读

2、数据库认证、安全模式
db.auth("userName", "123123");

3、显示当前所有用户
show users;

4、删除用户
db.removeUser("userName");

Ø 其他

1、查询之前的错误信息
db.getPrevError();

2、清除错误记录
db.resetError();

 

三、Collection聚集集合操作

Ø 查看聚集集合基本信息


1、查看帮助
db.yourColl.help();

2、查询当前集合的数据条数
db.yourColl.count();

3、查看数据空间大小
db.userInfo.dataSize();

4、得到当前聚集集合所在的db
db.userInfo.getDB();

5、得到当前聚集的状态
db.userInfo.stats();

6、得到聚集集合总大小
db.userInfo.totalSize();

7、聚集集合储存空间大小
db.userInfo.storageSize();

8、Shard版本信息
db.userInfo.getShardVersion()

9、聚集集合重命名
db.userInfo.renameCollection("users");
将userInfo重命名为users

10、删除当前聚集集合
db.userInfo.drop();

Ø 聚集集合查询

1、查询所有记录
db.userInfo.find();
相当于:select * from userInfo;
默认每页显示20条记录,当显示不下的情况下,可以用it迭代命令查询下一页数据。注意:键入it命令不能带“;”
但是你可以设置每页显示数据的大小,用DBQuery.shellBatchSize = 50;这样每页就显示50条记录了。

2、查询去掉后的当前聚集集合中的某列的重复数据
db.userInfo.distinct("name");
会过滤掉name中的相同数据
相当于:select distict name from userInfo;

3、查询age = 22的记录
db.userInfo.find({"age": 22});
相当于: select * from userInfo where age = 22;

4、查询age > 22的记录
db.userInfo.find({age: {$gt: 22}});
相当于:select * from userInfo where age > 22;

5、查询age < 22的记录
db.userInfo.find({age: {$lt: 22}});
相当于:select * from userInfo where age < 22;

6、查询age >= 25的记录
db.userInfo.find({age: {$gte: 25}});
相当于:select * from userInfo where age >= 25;

7、查询age <= 25的记录
db.userInfo.find({age: {$lte: 25}});

8、查询age >= 23 并且 age <= 26
db.userInfo.find({age: {$gte: 23, $lte: 26}});

9、查询name中包含 mongo的数据
db.userInfo.find({name: /mongo/});
//相当于%%
select * from userInfo where name like ‘%mongo%’;

10、查询name中以mongo开头的
db.userInfo.find({name: /^mongo/});
select * from userInfo where name like ‘mongo%’;

11、查询指定列name、age数据
db.userInfo.find({}, {name: 1, age: 1});
相当于:select name, age from userInfo;
当然name也可以用true或false,当用ture的情况下河name:1效果一样,如果用false就是排除name,显示name以外的列信息。

12、查询指定列name、age数据, age > 25
db.userInfo.find({age: {$gt: 25}}, {name: 1, age: 1});
相当于:select name, age from userInfo where age > 25;

13、按照年龄排序
升序:db.userInfo.find().sort({age: 1});
降序:db.userInfo.find().sort({age: -1});

14、查询name = zhangsan, age = 22的数据
db.userInfo.find({name: 'zhangsan', age: 22});
相当于:select * from userInfo where name = ‘zhangsan’ and age = ‘22’;

15、查询前5条数据
db.userInfo.find().limit(5);
相当于:select top 5 * from userInfo;

16、查询10条以后的数据
db.userInfo.find().skip(10);
相当于:select * from userInfo where id not in (
select top 10 * from userInfo
);

17、查询在5-10之间的数据
db.userInfo.find().limit(10).skip(5);
可用于分页,limit是pageSize,skip是第几页*pageSize

18、or与 查询
db.userInfo.find({$or: [{age: 22}, {age: 25}]});
相当于:select * from userInfo where age = 22 or age = 25;

19、查询第一条数据
db.userInfo.findOne();
相当于:select top 1 * from userInfo;
db.userInfo.find().limit(1);

20、查询某个结果集的记录条数
db.userInfo.find({age: {$gte: 25}}).count();
相当于:select count(*) from userInfo where age >= 20;

21、按照某列进行排序
db.userInfo.find({sex: {$exists: true}}).count();
相当于:select count(sex) from userInfo;

Ø 索引

1、创建索引
db.userInfo.ensureIndex({name: 1});
db.userInfo.ensureIndex({name: 1, ts: -1});

2、查询当前聚集集合所有索引
db.userInfo.getIndexes();

3、查看总索引记录大小
db.userInfo.totalIndexSize();

4、读取当前集合的所有index信息
db.users.reIndex();

5、删除指定索引
db.users.dropIndex("name_1");

6、删除所有索引索引
db.users.dropIndexes();

Ø 修改、添加、删除集合数据

1、添加
db.users.save({name: ‘zhangsan’, age: 25, sex: true});
添加的数据的数据列,没有固定,根据添加的数据为准

2、修改
db.users.update({age: 25}, {$set: {name: 'changeName'}}, false, true);
相当于:update users set name = ‘changeName’ where age = 25;

db.users.update({name: 'Lisi'}, {$inc: {age: 50}}, false, true);
相当于:update users set age = age + 50 where name = ‘Lisi’;

db.users.update({name: 'Lisi'}, {$inc: {age: 50}, $set: {name: 'hoho'}}, false, true);
相当于:update users set age = age + 50, name = ‘hoho’ where name = ‘Lisi’;

3、删除
db.users.remove({age: 132});

4、查询修改删除
db.users.findAndModify({
    query: {age: {$gte: 25}},
    sort: {age: -1},
    update: {$set: {name: 'a2'}, $inc: {age: 2}},
    remove: true
});

db.runCommand({ findandmodify : "users",
    query: {age: {$gte: 25}},
    sort: {age: -1},
    update: {$set: {name: 'a2'}, $inc: {age: 2}},
    remove: true
});

updateremove 其中一个是必须的参数; 其他参数可选。

 

参数 详解 默认值
query 查询过滤条件 {}
sort 如果多个文档符合查询过滤条件,将以该参数指定的排列方式选择出排在首位的对象,该对象将被操作 {}
remove 若为true,被选中对象将在返回前被删除 N/A
update 一个 修改器对象 N/A
new 若为true,将返回修改后的对象而不是原始对象。在删除操作中,该参数被忽略。 false
fields 参见Retrieving a Subset of Fields (1.5.0+) All fields
upsert 创建新对象若查询结果为空。 示例 (1.5.4+) false

Ø 语句块操作

1、简单Hello World
print("Hello World!");
这种写法调用了print函数,和直接写入"Hello World!"的效果是一样的;

2、将一个对象转换成json
tojson(new Object());
tojson(new Object('a'));

3、循环添加数据
> for (var i = 0; i < 30; i++) {
... db.users.save({name: "u_" + i, age: 22 + i, sex: i % 2});
... };
这样就循环添加了30条数据,同样也可以省略括号的写法
> for (var i = 0; i < 30; i++) db.users.save({name: "u_" + i, age: 22 + i, sex: i % 2});
也是可以的,当你用db.users.find()查询的时候,显示多条数据而无法一页显示的情况下,可以用it查看下一页的信息;

4、find 游标查询
>var cursor = db.users.find();
> while (cursor.hasNext()) {
    printjson(cursor.next());
}
这样就查询所有的users信息,同样可以这样写
var cursor = db.users.find();
while (cursor.hasNext()) { printjson(cursor.next); }
同样可以省略{}号

5、forEach迭代循环
db.users.find().forEach(printjson);
forEach中必须传递一个函数来处理每条迭代的数据信息

6、将find游标当数组处理
var cursor = db.users.find();
cursor[4];
取得下标索引为4的那条数据
既然可以当做数组处理,那么就可以获得它的长度:cursor.length();或者cursor.count();
那样我们也可以用循环显示数据
for (var i = 0, len = c.length(); i < len; i++) printjson(c[i]);

7、将find游标转换成数组
> var arr = db.users.find().toArray();
> printjson(arr[2]);
用toArray方法将其转换为数组

8、定制我们自己的查询结果
只显示age <= 28的并且只显示age这列数据
db.users.find({age: {$lte: 28}}, {age: 1}).forEach(printjson);
db.users.find({age: {$lte: 28}}, {age: true}).forEach(printjson);
排除age的列
db.users.find({age: {$lte: 28}}, {age: false}).forEach(printjson);

9、forEach传递函数显示信息
db.things.find({x:4}).forEach(function(x) {print(tojson(x));});
上面介绍过forEach需要传递一个函数,函数会接受一个参数,就是当前循环的对象,然后在函数体重处理传入的参数信息。

[转载]MongoDB实战开发 【零基础学习,附完整Asp.net示例】 - Fish Li - 博客园

mikel阅读(1156)

[转载]MongoDB实战开发 【零基础学习,附完整Asp.net示例】 – Fish Li – 博客园.

【目标】:本文将以实战的形式,向您展示如何用C#访问MongoDB,完成常见的数据库操作任务, 同时,也将介绍MongoDB的客户端(命令行工作模式)以及一些基础的命令。

【说明】:MongoDB是什么?有什么用?如果不清楚这些问题的,请自己google一下吧。

【适合对象】:完全没有接触MongoDB或对MongoDB有一点了解的C#开发人员。因此本文是一篇入门级的文章。

【示例项目】:本文的完整示例是一个简单的【客户,商品,订单】业务场景, 预览界面效果请点击此处(但并不完全相同),也包含下载示例项目的源码。

让我们开始MongoDB的实战入门吧。

下载MongoDB,并启动它

您可以在这个地址下载到MongoDB: http://www.mongodb.org/downloads, 本文将以【mongodb-win32-i386-1.8.2-rc2】来演示MongoDB的使用。

下载好了吗?我们继续吧。请解压缩您刚才下载的MongoDB的zip压缩包,进入解包的bin目录,会发现有一堆exe文件。 现在,请打开命令行窗口并切换到刚才的bin目录,然后输入以下命令:

这里,我运行了程序mongod.exe,并告诉它数据文件的保存目录(这个目录要事先创建好),至于mongod的更多命令行参数,请输入命令: mongod /? 来获得。
如果您也看到了这个界面,那么表示MongoDB的服务端已成功启动了。

顺便提一下:运行mongod后,它会显示一些有用的信息。比如:pid (进程ID), tcp port (监听端口), http 端口(用于查看运行状态), 操作系统版本,数据目录,32 or 64位版本,如果是32位版本,它还会告诉你【数据有2G的限制】,所以正式使用建议运行64位版本。

接下来,我们还要去下载MongoDB的C#驱动,它可以让我们在C#中使用MongoDB 。下载地址: https://github.com/samus/mongodb-csharp
我下载到的压缩包是:samus-mongodb-csharp-0.90.0.1-93-g6397a0f.zip 。这个压缩包本身也包含了一个Sample,有兴趣的可以看看它。
我们在C#访问MongoDB所需的驱动就是项目MongoDB了。编译这个项目就能得到了,文件名:MongoDB.dll

在C#使用MongoDB

好了,有了前面的准备工作,我们可以开始在C#中使用MongoDB了。不过,由于本示例项目的代码也不少,因此本文将只展示与MongoDB交互的相关代码, 更完整的代码请自行查阅示例项目。

接下来,本文演示通过C#完成【客户资料】的一些基本的数据操作,还是先来定义一个客户资料的类型吧。

public sealed class Customer
{
    [MongoId]
    public string CustomerID { get; set; }
    public string CustomerName { get; set; }
    public string ContactName { get; set; }
    public string Address { get; set; }
    public string PostalCode { get; set; }
    public string Tel { get; set; }
}

说明:这就是一个简单的类,而且代码中的[MongoId]也是可以不要的(这个后面再说)。

在操作数据库之前,我要说明一下:MongoDB在使用前,并不要求您事先创建好相应的数据库,设计数据表结构!
在MongoDB中,没有【表】的概念,取而代之的是【集合】,也没有【数据记录】的概念,取而代之的是【文档】, 我们可以把【文档】理解成一个【对象】,任意的对象,甚至可以有复杂的嵌套层次。
因此,我们不用再写代码从【数据表字段】到C#类的【属性,字段】的转换了,现在直接就可以读写整个对象了。
而且MongoDB不支持Join操作,所以,如果有【关联】操作,就需要你自己来处理。

再来定义二个变量:

private static readonly string _connectionString = "Server=127.0.0.1";

private static readonly string _dbName = "MyNorthwind";

新增记录

public void Insert(Customer customer)
{
    customer.CustomerID = Guid.NewGuid().ToString("N");

    // 首先创建一个连接
    using( Mongo mongo = new Mongo(_connectionString) ) {

        // 打开连接
        mongo.Connect();

        // 切换到指定的数据库
        var db = mongo.GetDatabase(_dbName);

        // 根据类型获取相应的集合
        var collection = db.GetCollection<Customer>();

        // 向集合中插入对象
        collection.Insert(customer);
    }
}

上面的代码中,每一行都有注释,这里就不再解释了。

删除记录

public void Delete(string customerId)
{
    using( Mongo mongo = new Mongo(_connectionString) ) {
        mongo.Connect();
        var db = mongo.GetDatabase(_dbName);
        var collection = db.GetCollection<Customer>();

        // 从集合中删除指定的对象
        collection.Remove(x => x.CustomerID == customerId);
    }
}

更新记录

public void Update(Customer customer)
{
    using( Mongo mongo = new Mongo(_connectionString) ) {
        mongo.Connect();
        var db = mongo.GetDatabase(_dbName);
        var collection = db.GetCollection<Customer>();

        // 更新对象
        collection.Update(customer, (x => x.CustomerID == customer.CustomerID));
    }
}

获取记录列表

public List<Customer> GetList(string searchWord, PagingInfo pagingInfo)
{
    using( Mongo mongo = new Mongo(_connectionString) ) {
        mongo.Connect();
        var db = mongo.GetDatabase(_dbName);
        var collection = db.GetCollection<Customer>();

        // 先创建一个查询
        var query = from customer in collection.Linq()
                    select customer;

        // 增加查询过滤条件
        if( string.IsNullOrEmpty(searchWord) == false )
            query = query.Where(c => c.CustomerName.Contains(searchWord) || c.Address.Contains(searchWord));

        // 先按名称排序,再返回分页结果.
        return query.OrderBy(x => x.CustomerName).GetPagingList<Customer>(pagingInfo);
    }
}

获取单个对象

public Customer GetById(string customerId)
{
    using( Mongo mongo = new Mongo(_connectionString) ) {
        mongo.Connect();
        var db = mongo.GetDatabase(_dbName);
        var collection = db.GetCollection<Customer>();

        // 查询单个对象
        return collection.FindOne(x => x.CustomerID == customerId);
    }
}

重构(简化)代码

从上面代码可以看出,操作MongoDB大致都是这样一个操作过程。

// 首先创建一个连接
using( Mongo mongo = new Mongo(_connectionString) ) {

    // 打开连接
    mongo.Connect();

    // 切换到指定的数据库
    var db = mongo.GetDatabase(_dbName);

    // 根据类型获取相应的集合
    var collection = db.GetCollection<Customer>();

    // 【访问collection,做你想做的操作】
}

针对这个问题,我提供一个包装类来简化MongoDB的使用。

简化后的CRUD代码如下:

public void Insert(Customer customer)
{
    customer.CustomerID = Guid.NewGuid().ToString("N");

    using( MyMongoDb mm = new MyMongoDb() ) {
        mm.GetCollection<Customer>().Insert(customer);
    }
}

public void Delete(string customerId)
{
    using( MyMongoDb mm = new MyMongoDb() ) {
        mm.GetCollection<Customer>().Remove(x => x.CustomerID == customerId);
    }
}

public void Update(Customer customer)
{
    using( MyMongoDb mm = new MyMongoDb() ) {
        mm.GetCollection<Customer>().Update(customer, (x => x.CustomerID == customer.CustomerID));
    }
}

public Customer GetById(string customerId)
{
    using( MyMongoDb mm = new MyMongoDb() ) {
        return mm.GetCollection<Customer>().FindOne(x => x.CustomerID == customerId);
    }
}

看了上面这些代码,您应该会觉得MongoDB的使用也很容易,对吧。
接下来,我来通过界面录入一些数据,来看看我录入的结果吧。

到这里,你或许想知道:MongoDB有没有一个自己的客户端来查看数据呢?因为总不能只依赖自己写代码来查看数据吧?
是的,MongoDB也提供了一个客户端来查看并维护数据库。接下来,我们再来看看如何使用MongoDB的客户端吧。

使用MongoDB的客户端查看数据

MongoDB自带一个JavaScript shell,它可以从命令行与MongoDB实例交互。这个shell非常有用,通过它可以管理操作、检查运行实例、查询数据等操作。
让我们再回到命令行窗口模式下吧(没办法,MongoDB只提供这种界面),运行mongo.exe ,如下图

这就是MongoDB的客户端的命令行模式了。通常我们在操作数据库前,要切换【当前数据】,
MongoDB也是一样,我们可以运行如下命令来查看数据库列表,并切换数据库,然后再查看集合列表,请看下图(我运行了三条命令)

注意:MongoDB区分名字的大小写。

在MongoDB中,查看【当前数据库】,可以使用命令【db】,
查看集合Customer的记录总数:【db.Customer.count();】
查看 CustomerId = 1 的记录:【db.Customer.findOne({“_id” : “1”});】,注意:查询条件是一个文档,这就是MongoDB的特色。
下图显示了上面三条命令的执行结果:

嗯,怎么有乱码?CustomerId = 1 的记录应该是这样的才对呀?

看到这一幕,您应该不要怀疑是MongoDB的错了,这个错误是由于MongoDB的客户端使用的编码是UTF-8, 而Windows 命令行程序 cmd.exe 使用的gb2312(我目前使用中文语言) 造成的。
解决办法:
1. 执行MongoDB的【exit】命令退回到Windows命令行状态(或者重新打开命令行窗口),
2. 运行命令:【chcp 65001】,切换到UTF-8编码下工作。
3. 设置命令行窗口的属性,请参考下图:

再运行 mongo 进入mongo命令行,切换数据库,并执行命令:【db.Customer.findOne({“_id” : “1”});】

现在可以看到汉字能正常显示了,但最后却显示”Failed to write to logfile”,对于这个问题,我们如果执行命令 【db.Customer.findOne({“_id” : “91”});】(id=91的记录就是我最后录入的,全是a的那条,前面截图上有), 可以发现没有任何异常发生,因此认为这个问题还是和cmd.exe有关的。 如果切换回 chcp 936 ,这时将看到乱码,但没有”Failed to write to logfile”,所以我将忽略这个错误。

使用MongoDB的客户端维护数据

下面我来演示一下如何使用MongoDB的客户端来执行一些基本的数据维护功能。还是从CRUD操作开始吧,请看下图,为了方便,我将在一个截图中执行多个命令。
注意:MongoDB的文档使用的是一种称为BSON格式的对象,与JavaScript中的JSON类似。

在上面的示例中,每个命令后,我加了一个红圈。在示例中,我先切换到 MyTest 数据库(它并不存在,但没关系), 然后我定义了一个文档 item 并插入到集合 table1 中,然后又定义了一个文档 item2,也插入到集合 table1 中。 注意:item , item2 的结构完全不同,但能放在一个集合中(不建议这样做)。最后调用 find() 显示集合中的所有文档。
此时,您有没有注意到:【每个文档有一个名为 “_id” 的成员】,我可没有定义啊。
其实,MongoDB会为每个文档都创建这样一个文档成员,我们指定的 “key”, “id” 对于MongoDB来说: 它们并不是【文档的主键】,MongoDB只认 “_id”,你可以指定,但如果不指定,MongoDB就自动添加。

此时,你可以看看前二张图片,可以发现:在定义Customer类时,有一个成员CustomerID此时却不存在! 我们可以再看一下Customer的定义:

public sealed class Customer
{
    [MongoId]
    public string CustomerID { get; set; }
    public string CustomerName { get; set; }
    public string ContactName { get; set; }
    public string Address { get; set; }
    public string PostalCode { get; set; }
    public string Tel { get; set; }
}

此时,您应该发现CustomerID这个成员有一个[MongoId]的特性。正是由于这个特性,驱动程序将把CustomerID映射为”_id”来使用。

好了,再次回到命令行,我要演示其它的命令。请看下图:

为了要更新某个文档,我们要使用findOne()方法找到要修改的文档对象,并将它保存一个变量t中,然后,修改它的属性, 接着调用update()方法就可以更新文档了,注意在调用update()时,第一个参数【更新范围】是采用文档的形式给出的, 第二参数才是要更新的新对象。在删除时,删除条件也是采用文档的形式指定的。处处使用文档,这就是MongoDB的特色。

前面的示例代码中,我使用了find()和findOne(),它们是有区别的:findOne()只返回一个文档对象,find()返回一个集合列表, 如果不指定过滤范围,它将返回整个集合,但在客户端中最多只显示前20个文档。

再来个复杂的查询:搜索日期范围是 2011-06-25 到 2011-06-26 之间的订单记录。由于返回的结果太长,我的截图将不显示它们。
注意:MongoDB的查询条件中,并没有 >, <, >= , <= 这些运算符,而是使用 “$lt”, “$lte”, “$gt”, “$gte” 这种方式作为文档的KEY来使用的, 因此一个简单的 OrderDate >= “2006-06-25” and OrderDate < “2006-06-26” 要写成如下方式:

如果遇到 or 就更麻烦了,如:CustomerId = 1 or CustomerId = 2 ,有二种写法:

语法不难,相信能看懂JSON的人,也能看懂这二条命令。

再来个分页的命令:

与LINQ的语法类似,好理解。

MongoDB客户端还支持其它的语法,这里就不一一介绍了。因为我们的目标是在C#中使用MongoDB,在MongoDB提供的C#驱动中, 我们并不需要写那样麻烦的查询条件,只需要按LINQ的语法写查询就可以了,因此会很容易使用。 不过,有些维护性的操作,我们只能通过命令的方式去执行,比如:删除集合,删除数据库。

执行【db.runCommand({“drop” : “table1”});】便可以删除一个集合,也可以执行命令【db.table1.drop();】,二者的效果是一样的。
再来看看如何删除数据库的命令:

注意:命令【db.runCommand({“dropDatabase”: 1});】只能删除【当前数据库】,所以要先切换当前数据库, 然后执行这个命令,执行删除数据库的命令后,我们再用命令【show dbs;】,发现数据库【MyTest】已不存在,即删除成功。 删除数据库还有一个方法:还记得我前面启动mongod.exe时给它传递了一个参数 【-dbpath “H:\AllTempFiles\mongodb\data”】吗? 我们现在去那个目录看一下有什么东西。

看了这张图,您有没有想过:这二个以【MyNorthwind】开头的文件会不会就是数据库的文件呢? 我现在就删除看看,先停止mongod.exe,然后删除文件(由于我目前只有一个数据库,我把目录下的文件全删除了),删除后:

现在,我再来启动mongod.exe,然后在客户端执行命令【show dbs;】看看:

现在可以发现我们之前的【MyNorthwind】数据库没有了,当然也就是删除了。 说明一下:现在这二个数据库,是MongoDB自带的,用于特殊用途的,我们可以不理会它们。

好了,我们还是再来看看MongoDB提供的C#驱动提供了什么东西吧。

MongoDB提供的C#驱动

我把MongoDB提供的C#驱动中认为比较重要的类做了个截图:

再来看看我前面给出一段操作MongoDB的代码:

// 首先创建一个连接
using( Mongo mongo = new Mongo(_connectionString) ) {

    // 打开连接
    mongo.Connect();

    // 切换到指定的数据库
    var db = mongo.GetDatabase(_dbName);

    // 根据类型获取相应的集合
    var collection = db.GetCollection<Customer>();

    // 【访问collection,做你想做的操作】
}

这段代码大致也说明了在C#中操作MongoDB的一个过程,主要涉及上图中的前三个类,这三个类也是最核心的类。 这里值得一提的是:LinqExtensions.Linq()方法可以让我们在写查询时, 方便地使用LINQ的优雅语法,而不是一堆复杂的文档条件!这也是我选择这个驱动的原因。

还记得我前面举过几个在命令行中调用runCommand的示例吗?如果在C#中也需要执行这样的操作,可以调用MongoDatabase.SendCommand() 方法。比如:删除集合Category,我们可以写成:

void DeleteCategoryCollection()
{
    using( MyMongoDb mm = new MyMongoDb() ) {
        mm.CurrentDb.SendCommand(new Document("drop", "Category"));
    }
}

【MongoIdAttribute】:可以让我们将一个C#类的数据成员映射到文档的”_id”属性。前面有示例说明,这里就不再多说了。

【MongoAliasAttribute】:可以让我们将一个C#类的数据成员在映射到文档时采用其它的属性名称。
比如:我希望将CustomerName成员在保存到MongoDB时,采用CName来保存。

[MongoAlias("CName")]
public string CustomerName { get; set; }

【MongoIgnoreAttribute】:可以让一个C#类在保存到MongoDB时,忽略某些成员。请看下面的代码:

public sealed class OrderItem : MyDataItem
{
    [MongoId]        // 这个成员将映射到 "_id"
    public string OrderID { get; set; }

    [ScriptIgnore]    // 在JSON序列化时,忽略这个成员
    public DateTime OrderDate { get; set; }

    [MongoIgnore]    // 在保存到MongoDB时,忽略这个成员
    public string CustomerName { get; set; }

    // .... 还有其它的属性。

    // 加这个属性仅仅为了在客户端中能更容易的显示,要不然,客户端处理格式转换实在是麻烦。
    // 它将不会被写入到数据库。
    [MongoIgnore]
    public string OrderDateText { get { return this.OrderDate.ToString("yyyy-MM-dd HH:mm:ss"); } }
}

MongoDB不支持在查询数据库时使用Join操作

在MongoDB中,一个文档就是一个完整的对象,所以获取一个对象时,并不需要关系数据库的那种JOIN语法。 在上面定义的OrderItem中,CustomerName并没有保存到数据库,而是在加载时,采用了【引用】的设计方式, 根据CustomerID去访问集合Customer来获取对应的CustomerName ,这也算是JOIN的常见使用场景了。

示例项目中有一个需求:根据一个日期范围查询订单列表(支持分页)。我是这样实现这个查询操作的。

/// <summary>
/// 根据指定的查询日期范围及分页参数,获取订单记录列表
/// </summary>
/// <param name="dateRange">日期范围</param>
/// <param name="pagingInfo">分页参数</param>
/// <returns>订单记录列表</returns>
public List<OrderItem> Search(QueryDateRange dateRange, PagingInfo pagingInfo)
{
    dateRange.EndDate = dateRange.EndDate.AddDays(1);

    using( MyMongoDb mm = new MyMongoDb() ) {
        var collection = mm.GetCollection<OrderItem>(STR_Orders);

        var query = from ord in collection.Linq()
                    where ord.OrderDate >= dateRange.StartDate && ord.OrderDate < dateRange.EndDate
                    orderby ord.OrderDate descending
                    select new OrderItem {
                        OrderID = ord.OrderID,
                        CustomerID = ord.CustomerID,
                        OrderDate = ord.OrderDate,
                        SumMoney = ord.SumMoney,
                        Finished = ord.Finished
                    };

        // 获取订单列表,此时将返回符合分页的结果。
        List<OrderItem> list = query.GetPagingList<OrderItem>(pagingInfo);


        // 获取订单列表中所有的客户ID
        string[] cids = (from ord in list 
                         where string.IsNullOrEmpty(ord.CustomerID) == false
                         select ord.CustomerID)
                         .Distinct()
                         .ToArray();

        // 找到所有客户记录
        Dictionary<string, Customer> customers =
                            (from c in mm.GetCollection<Customer>().Linq()
                             where cids.Contains(c.CustomerID)
                             select new Customer {
                                 CustomerID = c.CustomerID,
                                 CustomerName = c.CustomerName
                             })
                            .ToDictionary(x => x.CustomerID);

        // 为订单列表结果设置CustomerName
        foreach( OrderItem ord in list ) {
            Customer c = null;
            if( string.IsNullOrEmpty(ord.CustomerID) == false && customers.TryGetValue(ord.CustomerID, out c) )
                ord.CustomerName = c.CustomerName;
            else 
                ord.CustomerName = string.Empty;
        }

        return list;
    }
}

获取MongoDB服务端状态

我们再来看一下当时启动服务端的截屏吧:

注意最后一行,它告诉我们它有一个WEB接口,端口是 28017 ,现在我就去看看那是个什么样子的。

可以看到它提供了一些服务端的状态信息。 我们还可以通过访问【http://localhost:28017/_status】来获得以JSON方式的统计信息。

我们还可以通过运行客户端的命令【db.runCommand({“serverStatus” : 1});】来获取这些信息:

好了,就说到这里吧。接下来,您也可以写点代码尝试一下,或者下载我准备的示例项目参考一下。

点击此处下载示例代码

[转载]MongoDB常用命令 - dayang - 博客园

mikel阅读(1084)

[转载]MongDB – dayang – 博客园.

启动方式一:执行命令行  mongod.exe -dbpath D:\data\db          -dbpath为数据库存放路径命令,后面空格加路径(注意路径不能存在空格)

启动方式二:以windows服务方式安装MongoDB服务;

–fork 守护进程

执行命令行 mongod –install –logpath c:\mongodblog –dbpath d:\data\db

–logpath 为设置日志文件,日志文件路径必须指向文件而不是一个目录

  –install –dbpath D:\MongoDB\win32\data –logpath D:\MongoDB\win32\mongodb.log
修改默认端口:
–port
$ ./mongdb –port 20111
把服务端口修改为20111,这个一方面是为了安全,使用默认端口容易被一些恶意的人发现做手脚

 

Mongodb 删除

提供一个命令

mongodb  –dbpath D:\MongoDB\win32\data –logpath D:\MongoDB\win32\mongodb.log -remove

当然也可以使用sc delete MongoDB来删除服务项

最好还是在注册表去找mongo的选项,并一一删除 重启在重新安装

 

Mongodb的关闭:
前台运行:
如果没有使用–fork,直接可以前台退出终端关闭。通过这种方式,Mongodb将会自己做清理退出,把没有写好的数据写完成,并最终关闭数据文件。要注意的是这个过程会持续到所有操作都完成。
后台运行:
如果使用–fork在后台运行mongdb服务,那么就要通过向服务器发送shutdownServer()消息来关闭。
1、普通命令:
$ ./mongod
> use admin
> db.shutdownServer()
要注意的是,这个命令只允许在本地,或是一个经过认证的客户端。
2、如果这是一个主从式的复制集群,在1.9.1版本后将按下面的步骤来关闭
  • 检查从Mongodb的数据更新时间
  • 如果所有的从Mongodb和主的时间差都超过10,这个时候不会关闭mongodb(在这种情况下面,我们可以通过配置timeoutSecs的方式来让从Mongodb完成数据的更新)
  • 如果其中有一个从Mongodb与主服务时间差在10秒内,那么主服务器将会关闭,并且等待从Mongodb更新完成并关闭。
3、如果没有up-to-date 从Mongodb且你想强制关闭服务,可以通过添加force:true;命令如下:
> db.adminCommand({shutdown : 1, force : true})
> //or
> db.shutdownServer({force : true})
4、指定特定超时时间的关闭服务器,命令同上,另外加上一个timeoutsec:参数
> db.adminCommand(shutdown : 1, force : true, timeoutsec : 5)
> db.shutdownServer({force : true, timeoutsec : 5})

配置文件(外部配文件置):

mongod –config D:\mongodb\mongodb.config

mongodb.config文件内容:

port = 20000 dbpath = D:/mongodb/dbs logpath = D:/mongodb/logs.log
logappend = true

正确停止MongoDB:

mongo -port 20000 use admin db.shutdownServer();

安全认证:

  1.添加用户

   db.addUser(username, password,[ readOnly=false])

[ readOnly=false]参数可选,如果为true,用户只有查询权限。

admin数据库下面添加的用户  被视为超级用户(管理员)。

2.用户认证 db.auth(username, password)

3.重启服务端,加入 –auth命令选项  开启安全检查

mongod –dbpath D:/mongodb/db  –port 20000 –logpath = D:/mongodb/logs.log –logappend –auth

例子:

1. 添加一个超级用户:

a.添加用户

>mongo -port 20000 > use admin switched to db admin > db.addUser(“admin”,”admin123″); { “n” : 0, “connectionId” : 4, “err” : null, “ok” : 1 } {         “user” : “admin”,         “readOnly” : false,         “pwd” : “6f09f2f35e3a5e225af66fe3868e4fb7”,         “_id” : ObjectId(“50114eb027e4ae802c6bda45”) } >

b.认证用户

> use admin switched to db admin > db.auth(“admin”,”admin123″); 1

c.重启服务端 加入–auth参数

登录后不能正常查询

>mongo –port 20000 test MongoDB shell version: 2.0.4 connecting to: 127.0.0.1:20000/test > db.test.find(); error: {         “$err” : “unauthorized db:test lock type:-1 client:127.0.0.1”,         “code” : 10057 } >

d.使用用户名 密码登录

>mongo –port 20000 admin  -u admin -p MongoDB shell version: 2.0.4 Enter password: connecting to: 127.0.0.1:20000/admin > use test switched to db test > db.test.find(); >

2.添加一个普通用户

> use test switched to db test > db.addUser(“abc”,”abc123″); { “n” : 0, “connectionId” : 9, “err” : null, “ok” : 1 } {         “user” : “abc”,         “readOnly” : false,         “pwd” : “30fc2d5cc077f71cc81d3c82afc9d361”,         “_id” : ObjectId(“501157ed1d2319c203e2e8d3”) }

认证:

> db.auth(“abc”,”abc123″); 1

用户名 密码登录

mongo –port 20000 test  -u abc -p MongoDB shell version: 2.0.4 Enter password: connecting to: 127.0.0.1:20000/test > db.test.find();

查询用户

db.system.users.find()

删除用户:

db.system.users.remove({user:”admin”});

限制ip访问:

使用–bindip 参数, 只能被–bindip参数指定的ip地址访问.

如:mongod –bindip localhost

数据文件备份:

>mongodump -port 20000 -d test -u admin -p-d test

备份的数据库名称会在当前目录下创建一个dump目录,用于存放备份出来的文件,当然也可以(-o)指定备份存放的目录。

mongodump -port 20000 -d test -o c:/ -u admin -p

mongodump –help 查看其他选项

数据恢复:

>mongorestore -port 20000 -d test –directoryperdb c:/test/  –drop -u admin -p

–directoryperdb指定备份的目录

–drop 恢复的时候先删除

例:

a,先删除test数据库

> use test; switched to db test > db.dropDatabase(); { “dropped” : “test”, “ok” : 1 } > show dbs; admin   0.03125GB local   (empty)

b.恢复

mongorestore -port 20000 -d test –directoryperdb c:/test/  –drop -u admin -p

监控:

1.serverStatus命令

use admin db.serverStatus();

db.serverStatus(); {         “host” : “admin:20000”,         “version” : “2.0.4”,         “process” : “mongod”,         “uptime” : 16,         “uptimeEstimate” : 14,         “localTime” : ISODate(“2012-07-26T13:26:38.375Z”),         “globalLock” : {                 “totalTime” : 15421875,                 “lockTime” : 0,                 “ratio” : 0,                 “currentQueue” : {                         “total” : 0,                         “readers” : 0,                         “writers” : 0                 },                 “activeClients” : {                         “total” : 0,                         “readers” : 0,                         “writers” : 0                 }         },         “mem” : {                 “bits” : 32,                 “resident” : 15,                 “virtual” : 57,                 “supported” : true,                 “mapped” : 0         },         “connections” : {                 “current” : 1,                 “available” : 19999         },         “extra_info” : {                 “note” : “fields vary by platform”,                 “page_faults” : 4032,                 “usagePageFileMB” : 19,                 “totalPageFileMB” : 3871,                 “availPageFileMB” : 2878,                 “ramMB” : 1977         },         “indexCounters” : {                 “note” : “not supported on this platform”         },         “backgroundFlushing” : {                 “flushes” : 0,                 “total_ms” : 0,                 “average_ms” : 0,                 “last_ms” : 0,                 “last_finished” : ISODate(“1970-01-01T00:00:00Z”)         },         “cursors” : {                 “totalOpen” : 0,                 “clientCursors_size” : 0,                 “timedOut” : 0         },         “network” : {                 “bytesIn” : 220,                 “bytesOut” : 261,                 “numRequests” : 3         },         “opcounters” : {                 “insert” : 0,                 “query” : 1,                 “update” : 0,                 “delete” : 0,                 “getmore” : 0,                 “command” : 4         },         “asserts” : {                 “regular” : 0,                 “warning” : 0,                 “msg” : 0,                 “user” : 0,                 “rollovers” : 0         },         “writeBacksQueued” : false,         “ok” : 1

返回字段说明:

uptime: 服务器运行时间(秒)。

localTime: 服务器本地时间。

mem: 服务器内存隐身了多少数据,服务器进程的虚拟内存和常驻内存占用情况(单位:MB)。

connections: 当前连接数。

opcounters: 操作统计。

globalLock:表示全局写入锁占用的服务器时间(单位:微妙) ;

backgroundFlushing: 表示后台做了多少次fsync以及用了多少时间。

asserts:统计断言的次数。

2.mongostat.exe

bin目录下。

[转载]Mongodb windows下安装 - 陈朋 - 博客园

mikel阅读(1290)

[转载]Mongdb windows下安装 – 陈朋 – 博客园.

网上还是有很多这方面的教程的,安装时比较顺利。

安装文件:官方网站 http://www.mongodb.org/downloads

选择对应自己系统的文件。

一、解压缩文件。

将压缩包解压。我的目录为E:\mongdb\mongdb

二、建立工作目录。

1、建立数据存放目录 E:\mongodb\data\db

2、建立日志文件       E:\mongodb\log\mongodb.log

三、启动mongdb服务。

控制台进入解压后的工作目录,输入命令

E:\mongodb\mongodb\bin>E:\mongodb\mongodb\bin\mongod.exe --dbpath=E:\mongodb\data\db

正常运行应该显示以下内容

Thu Apr 12 00:24:39 [initandlisten] MongoDB starting : pid=6832 port=27017 dbpath=E:\mongodb\data\db 64-bit host=chen-PC
Thu Apr 12 00:24:39 [initandlisten] db version v2.0.4, pdfile version 4.5
Thu Apr 12 00:24:39 [initandlisten] git version: 329f3c47fe8136c03392c8f0e548506cb21f8ebf
Thu Apr 12 00:24:39 [initandlisten] build info: windows sys.getwindowsversion(major=6, minor=1, build=7601, platform=2, service_pack='Service Pack 1') BOOST_LIB_VERSION=1_42
Thu Apr 12 00:24:39 [initandlisten] options: { dbpath: "E:\mongodb\data\db" }
Thu Apr 12 00:24:39 [initandlisten] journal dir=E:/mongodb/data/db/journal
Thu Apr 12 00:24:39 [initandlisten] recover : no journal files present, no recovery needed
Thu Apr 12 00:24:40 [initandlisten] waiting for connections on port 27017
Thu Apr 12 00:24:40 [websvr] admin web console waiting for connections on port 28017

Mongdb默认的监听端口为27017。

如果没有请求信息,mongdb每隔5分钟会显示一条信息。

Thu Apr 12 00:25:40 [clientcursormon] mem (MB) res:21 virt:82 mapped:0
Thu Apr 12 00:30:40 [clientcursormon] mem (MB) res:21 virt:79 mapped:0
Thu Apr 12 00:35:40 [clientcursormon] mem (MB) res:21 virt:79 mapped:0
Thu Apr 12 00:37:19 [initandlisten] connection accepted from 127.0.0.1:63584 #1
Thu Apr 12 00:40:40 [clientcursormon] mem (MB) res:21 virt:80 mapped:0
Thu Apr 12 00:45:40 [clientcursormon] mem (MB) res:21 virt:80 mapped:0

四、将mongdb作为windows服务随机启动。

1、输入命令。

E:\mongodb\mongodb\bin>E:\mongodb\mongodb\bin\mongod.exe --dbpath=E:\mongodb\data\db --logpath=E:\mongodb\logs\mongodb.log --install

正确情况下显示以下内容

all output going to: E:\mongodb\logs\mongodb.log

2、开启服务,输入命令。

net start mongodb

五、客户端验证连接。

新开一个cmd窗口,输入命令。

E:\mongodb\mongodb\bin\mongo

会输出以下内容

MongoDB shell version: 2.0.4
connecting to: test

哈哈,开始吧!

[转载]Node.js和Geddy初学者指南 - 第三部分:使用Mongdb持久化你的数据 - gbin1 - 博客园

mikel阅读(1019)

[转载]Node.js和Geddy初学者指南 – 第三部分:使用Mongdb持久化你的数据 – gbin1 – 博客园.

在这个三个部分的教程中,我们教大家使用Node.js和Geddy来创建了一个todo的管理应用,上一篇我们将数据保存在内存中,在这个系列最后一篇文章中,我们将介绍如何将todo项目保存到mongodb中。

介绍MongoDB

MongoDB是一个由10gen开发的NoSQL类型的数据库。这是node应用可以使用的超棒的数据库,它将数据保存为JSON格式。并且所有的查询都是使用JavaScript开发的。如果你想深入了解Mongdb,请参考这两篇文章:Nosql数据库教程之初探MongoDB – 第一部分Nosql数据库教程之初探MongoDB – 第二部分。相信大家会有个基本的使用概念。

安装mongodb

到如下地址下载mongodb:

http://www.mongodb.org/downloads

安装很简单,你可以参考上面文章内容。

MongoDB-Wrapper

对于我们的应用来说,我们使用一个模块来包装mongdb-native数据驱动。这很大的简化了代码,我们安装后进入你的应用并且执行如下:

npm install mongodb-wrapper

如果没有错误的话,你可以看到一个mongdb-wrapper目录出现在你的node_modules目录。

设置你的数据库

Mongdb非常简单,你不需要担心设置表,列或者数据库,简单的连接到数据库。就创建了一个!只需要添加到collection。接下来我们设置我们的应用。

编辑你的init.js文件

我们需要应用范围中访问DB ,所以我们添加代码到config/init.js。你可以看到如下:

复制代码
// Add uncaught-exception handler in prod-like environments
if (geddy.config.environment != 'development') {
  process.addListener('uncaughtException', function (err) {
    geddy.log.error(JSON.stringify(err));
  });
}
geddy.todos = [];
geddy.model.adapter = {};
geddy.model.adapter.Todo = require(process.cwd() + '/lib/model_adapters/todo').Todo;

Let’s add in our db code at the very top (and remove the geddy.todos array while we’re at it):

var mongo = require('mongodb-wrapper');

geddy.db = mongo.db('localhost', 27017, 'todo');
geddy.db.collection('todos');

// Add uncaught-exception handler in prod-like environments
if (geddy.config.environment != 'development') {
  process.addListener('uncaughtException', function (err) {
    geddy.log.error(JSON.stringify(err));
  });
}
geddy.model.adapter = {};
geddy.model.adapter.Todo = require(process.cwd() + '/lib/model_adapters/todo').Todo;
复制代码

首先我们要求mongdb-wrapper模块。然后我们设置我们的数据库,添加collection到数据库中,几乎不需要做太多。

重写我们的Modeal-Adapter

Geddy并不在乎你使用的后台,只要是使用MVC架构书写就好。这意味着你需要修改数据写入的部分都在model-adapter中。同时也注意这是一个adapter的完全重写,所以如果你需要保持使用内存保存数据的话,你需要将它备份到其它目录中。

编辑你的Save方法

打开model-adapter(lib/model_adapters/todo.js),找到save方法。应该如下:

复制代码
this.save = function (todo, opts, callback) {
  if (typeof callback != 'function') {
    callback = function(){};
  }
  var todoErrors = null;
  for (var i in geddy.todos) {
    // if it's already there, save it
    if (geddy.todos[i].id == todo.id) {
      geddy.todos[i] = todo;
      todoErrors = geddy.model.Todo.create(todo).errors;
      return callback(todoErrors, todo);
    }
  }
  todo.saved = true;
  geddy.todos.push(todo);
  return callback(null, todo);
}
复制代码

修改成如下:

复制代码
this.save = function (todo, opts, callback) {
  // sometimes we won't need to pass a callback
  if (typeof callback != 'function') {
    callback = function(){};
  }
  // Mongo doesn't like it when you send functions to it
  // so let's make sure we're only using the properties
  cleanTodo = {
    id: todo.id
  , saved: todo.saved
  , title: todo.title
  , status: todo.status
  };
  // Double check to see if this thing is valid
  todo = geddy.model.Todo.create(cleanTodo);
  if (!todo.isValid()) {
    return callback(todo.errors, null);
  }
  // Check to see if we have this to do item already
  geddy.db.todos.findOne({id: todo.id}, function(err, doc){
    if (err) {
      return callback(err, null);
    }
    // if we already have the to do item, update it with the new values
    if (doc) {
      geddy.db.todos.update({id: todo.id}, cleanTodo, function(err, docs){
        return callback(todo.errors, todo);
      });
    }
    // if we don't already have the to do item, save a new one
    else {
      todo.saved = true;
      geddy.db.todos.save(todo, function(err, docs){
        return callback(err, docs);
      });
    }
  });
}
复制代码

不要被这些代码弄晕了,这是最复杂的一个。记住我们的save方法必须同时处理新的todo和更新todo俩个操作。接下来我们详细介绍代码。

我们使用同样的callback方法,如果我们没有callback方法,那么使用一个空的方法。

然后我们处理todo项目。我们必须这样做的原因在于我们的todo对象拥有JavaScript的方法(类似save),但是Mongo不希望你们传递对象的时候包含方法。因此我们需要创建一个新的对象,只包含我们需要的属性。

然后,我们判断todo是否合法。如果不的话,我们调用带有验证错误的callback 。如果合法,就继续。

为 了避免我们在数据库中已经包含了todo数据,我们检查是否todo存在。这里开始我们使用mongodb-wrapper模块。它提供了我们一个干净的 API来和数据库交互。这里我们使用db.todos.findOne()方法来找到一个简单document来满足我们的查询。我们的查询是一个简单 js对象 – 我们查找一个id和todo的id一样的documen。如果我们找到一个并且没有报错,我们使用db.todos.update()方法来更新 document中的数据。如果没有找到,我们使用db.todos.save()方法来保存一个新的包含todo项目的document。

在所有的情况中,完成后我们都调用一个callback,所有我们得到的错误和db返回的docs都将传递到这个callback中。

编辑all方法

首先我们看看all方法,应该类似下面:

this.all = function (callback) {
  callback(null, geddy.todos);
}

我们修改成这样:

复制代码
this.all = function (callback) {
  var todos = [];
  geddy.db.todos.find().sort({status: -1, title: 1}).toArray(function(err, docs){
    // if there's an error, return early
    if (err) {
      return callback(err, null);
    }
    // iterate through the docs and create models out of them
    for (var i in docs) {
      todos.push( geddy.model.Todo.create(docs[i]) )
    }
    return callback(null, todos);
  });
}
复制代码

比 save方法简单多了,对吧?我们使用db.todos.find()方法得到所有todos集合中的项目。我们使用mongdb-wrapper的 API通过status和标题来排序结果(降序排列)。然后我们传递到array,这个数组将触发查询。一旦我们得到数据,我们看看是否有错误,如果有, 我们调用错误的callback,如果没有,则继续。

然后,我们循环所有的docs(mongo返回的所有document内容),创建新的todo model实例,将他们推送到todos数组中。完毕后,我们调用callback,传递到todos。

编辑load方法

看看load方法,如下:

复制代码
this.load = function (id, callback) {
  for (var i in geddy.todos) {
    if (geddy.todos[i].id == id) {
      return callback(null, geddy.todos[i]);
    }
  }
  callback({message: "To Do not found"}, null);
};
复制代码

修改成:

复制代码
this.load = function (id, callback) {
  var todo;
  // find a todo in the db
  geddy.db.todos.findOne({id: id}, function(err, doc){
    // if there's an error, return early
    if (err) {
      return callback(err, null);
    }
    // if there's a doc, create a model out of it
    if (doc) {
      todo = geddy.model.Todo.create(doc);
    }
    return callback(null, todo);
  });
};
复制代码

这个更加简单。我们再次使用db.todos.findOne()方法。这一次,我们就这么用。如果遇到错误,我们调用callback,如果没有继续。如果我们得到了一个doc,我们创建一个新的todo model实例并且调用callback。

编辑remove方法

看看remove方法如下:

复制代码
this.remove = function(id, callback) {
  if (typeof callback != 'function') {
    callback = function(){};
  }
  for (var i in geddy.todos) {
    if (geddy.todos[i].id == id) {
      geddy.todos.splice(i, 1);
      return callback(null);
    }
  }
  return callback({message: "To Do not found"});
};
复制代码

修改为:

复制代码
this.remove = function(id, callback) {
  if (typeof callback != 'function') {
    callback = function(){};
  }
  geddy.db.todos.remove({id: id}, function(err, res){
    callback(err);
  });
}
复制代码

这个remove方法更加简单。使用db.todos.remove()方法来删除所有指定id的document并且调用一个带有error的callback。

最后的展示

最后让我们测试一下,cd到你的项目目录,使用geddy启动服务器。创建一个todo,编辑,使用错误的输入让它报错,删除,是不是都可以正常工作吧!

总结

我们希望通过这篇文章大家能够学习到Node.js,MongoDB和Geddy。如果你有什么好的建议或者意见,请给我们留言。谢谢!

欢迎访问GBin1.com

[转载]nodeJS+bootstarp+mongodb整一个TODO小例子 - 方方和圆圆 - 博客园

mikel阅读(1013)

[转载]nodeJS+bootstarp+mongodb整一个TODO小例子 – 方方和圆圆 – 博客园.又是一个简单的小玩意儿, 不过有个大玩意儿,就是noSQL的mongodb(文件大小:130M),  你要下载一个mongdodb, 去官方网站下载

  安装以后在mongodb的命令行目录下执行

1
mongod --dbpath=c:\mongodbInfo\ --port 27017

这个命令会在C盘新建一个叫做mongodInfo的目录用来保存mongodb的数据;

nodeJS要安装mongodb的依赖库, 通过npm进行安装

1
npm install mongodb

mongodb的API可以通过这里查看,打开API

这些是项目依赖, 其实就是express和mongodb这两个, 剩下的都是express自带的:’

"dependencies": {
"cookie-parser": "~1.3.3",
"debug": "~2.0.0",
"body-parser": "~1.8.4",
"express": "~4.9.8",
"jade": "~1.6.0",
"mongodb": "~1.3.23",
"morgan": "~1.3.2",
"serve-favicon": "~2.1.7"
}

完成的结果图是这样的:

因为我们这盘弄得是数据库, 所以起码要有一个连接数据库操作数据库的函数, mongodb的数据库接有很多种, 主要是因为版本不同, 接口有变, 但是还好的是高版本的数据库连接方式有做向前兼容,

这个模块做的事情是 连接数据库, 我们也可以通过实例化Col对collecionion(collectioninon就是mySQL中的table)进行删除添加collection:

//文档地址:http://mongodb.github.io/node-mongodb-native/1.4/
//mongodb已经更新到了2.0了,我勒个去;
var mongodb = require('mongodb');
//数据库连接的配置
var MONGOURL = "mongodb://localhost:27017/";

var open = function(name, callback) {
/*
//1.2版本和1.4版本mongodb的连接方式;,2.0的mongodb连接有向前兼容;
var server = new mongodb.Server('localhost', 27017, {auto_reconnect:true});
var db = new mongodb.Db(name, server, {safe:true});
db.open(function(err, db){
if(!err){
console.log('connect db');
callback&amp;&amp;callback(db);
};
});
*/
// 这样的连接方式还是比较好理解的;
var MongoClient = require('mongodb').MongoClient;
// name为数据库的名字;
var url = MONGOURL+ name;
MongoClient.connect(url, function(err, db) {
console.log('connect db');
callback&amp;&amp;callback(db);
});
};

/*
* @param dbName;
* instance @method create(colname, callback);
* instance @method remove(colname, callback);
* instance @method getDb();
*/
var Col = function(name,callback) {
//连接数据库;
open( name,function(_db) {
this.db = _db;
console.log("new db is done!")
callback&amp;&amp;callback( _db );
}.bind(this) );
};

Col.prototype = {
constructor : Col,
create : function( name, callback) {
this.db.createCollection( name, {safe:true}, function(err, collection){
if(err) {
console.log(err);
}else{
callback&amp;&amp;callback(collection);
};
});
},
remove : function( name, callback) {
this.db.dropCollection(name, {safe:true}, function(err,result) {
if(err) {
console.log(err);
return;
};
callback&amp;&amp;callback(result);
});
},
getDb : function() {
return this.db;
}
};

module.exports = Col;

 

以及数据表的操作我给独立出来Crud的js文件, 把Col回调的的数据库作为参数传进来就会返回一个对数据库表进行删改查增的方法, 接口参数为(collection的名字, 值, 回调函数):

  为nono这个表添加一条数据;
  crud.insert("nono" [{xx:xx}] , callback);
  更新nono这个表的所有hehe为1的所有字段为 lala为lala, 回调
  crud.update("nono", {hehe1 : 1} , { lala : "lala" },function(){console.log("update Done")});
  crud.remove("nono", {hehe : 0} ,function() {console.log("remove Done")});
  查找hehe为1的字段, 返回所有查找到的值;
  crud.find("nono", {hehe1 : 1} ,function(doc) {}
  所有的API在github的mongodb-native项目下有对应的API,打开API
//文档地址:http://mongodb.github.io/node-mongodb-native/1.4/
//mongodb已经更新到了2.0了,我勒个去;

var Crud = function(db) {
this.db = db;
};
Crud.prototype = {
constructor : Crud,
noop : function(){},
//增加
insert : function(col, val, cb) {
cb = cb || this.noop;
return this.db.collection(col).insert(val,cb);
},
//更新
update : function(col, search, val, cb) {
cb = cb || this.noop;
return this.db.collection(col).update(search, {$set : val}, cb);
},
//删除
remove : function(col,key,cb) {
cb = cb || this.noop;
//console.log(this.db.collection(col).remove);
return this.db.collection(col).remove(key,cb);
},

find : function(col,keyword,cb) {
cb = cb || this.noop;
this.db.collection(col).find(keyword).toArray(function(err, docs) {
cb(docs);
});
},
findBy_id : function(col,id, cb) {
this.db.collection(col).find({},{_id : id}, function(err, docs){
docs.toArray(function(err,doc){
cb(doc)
})
})
},
findOne : function(col,keyword,cb) {
cb = cb || this.noop;
this.db.collection(col).findOne(keyword,function(err, docs) {
cb(docs);
})
}
};

/*
需要把题目的数据库实例放进来;
var crud = new Crud(db);
var result = crud.insert("nono" [{xx:xx}] , callback);
var result = crud.update("nono", {hehe1 : 1} , { lala : "lala" },function(){console.log("update Done")});
var result = crud.remove("nono", {hehe : 0} ,function() {console.log("remove Done")});
var result = crud.find("nono", {hehe1 : 1} ,function(doc) {}
*/
module.exports = function(db) {
return new Crud(db);
};

界面的主要路由有首页,删除,添加,更新,这个四个, 我们要注意一下, 这里有个坑就是, 数据库中查询的id要通过 new ObjectId(id) 进行实例化以后的id, 你单单传一个字符串id是一点用都没有的:

var express = require('express');
var Col = require("../mongodb/Col.js");
var Crud = require("../mongodb/Crud.js");
var ObjectID = require('mongodb').ObjectID;

//路由是把第一个err给拿掉了;
var router = express.Router();

//初始化crud
var crud;
//新建DB并获取;
var db =new Col("todo",function(db){
//数据库连接完毕...
//创建一个RESTFUL对象;
crud = new Crud( db, function(){} );
});
/*
var data = {
title : "t0do",
lists : [
]
};
*/

//这个可以理解为app.get("/",function(req, res, next){});
/* GET 获取所有的列表. */
router.get('/', function(req, res) {
//因为db的新建连接是异步的,所以你如果新建数据库连接以后马上getDb不会失效,你获取的是undefined;
crud.find("todos",{},function(docs) {
console.log( docs );
res.render('index', {title : "todos", lists : docs});
});
});

/* GET 用户选择是否删除指定ID. */
router.get('/del/:id', function(req, res) {
res.render("delete",{id : req.params.id});
});

//用户确认删除指定id的todo
router.get("/del/ok/:id", function(req, res) {
var crud = new Crud(db.getDb());
var id = new ObjectID(req.params.id);

crud.remove("todos",{_id : id}, function() {
res.redirect("../../");
});
});

//获取编辑的todo信息界面
router.get('/modify/:id', function(req, res, next) {
var _id = new ObjectID( req.params.id );
crud.findOne("todos",{ _id : _id}, function(doc) {
doc.id = doc._id;
res.render("modify",doc);
});
});

//更新用户信息并重定向到主界面
router.post('/modify', function(req, res, next) {
var body = req.body;
console.log(body);
crud.update("todos",{_id : new ObjectID(body.id)}, {_id:new ObjectID(body.id),title:body.title,content:body.content},function() {
console.log("done");
});
res.redirect("../");
});

/* GET add listing. */
router.get('/add', function(req, res) {
res.render("add",{});
});

//默认的post值为新建, 从add界面调过来的;
router.post("/add",function(req, res) {
crud.insert("todos",[ {title : req.body.title, content : req.body.content }], function() {
console.log("success");
});
res.redirect("./");
});

module.exports = router;

demo的地址点击这里下载;

  完了;

[转载]一步一步来做WebQQ机器人-(三)(登录QQ并保持在线) - 上位者的怜悯 - 博客园

mikel阅读(1276)

[转载]一步一步来做WebQQ机器人-(三)(登录QQ并保持在线) – 上位者的怜悯 – 博客园.

全系列预计会有这些步骤,当然某些步骤可能会合并:

  • 验证码
  • 第一次登陆
  • 第二次登陆
  • 保持在线和接收消息
  • 获取好友和群列表
  • 发送消息
  • 变成智能的(*゚∀゚*)

 


 

 

首先看看这个请求

 

 

请求报文分析

 

 

  • referer是不可少的,先告诉TX的服务器请求是来自于这里:http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=2
  • post数据是一个json格式的: string.Format("r={{\"ptwebqq\":\"{0}\",\"clientid\":{1},\"psessionid\":\"\",\"status\":\"online\"}}", this.PtWebQQ, this.ClientID);

 

ptwebqq,是上一篇文章中从cookie中得到的值,不记得可以回去看看…

clientid是一个8长度的数字,如:29528322,作用是作为用户的唯一标识,可定义一个常量来表示,这个可随意输入

 

返回值:

 

 

retcode:0,表示成功

注意:result属性中的psessionidvfwebqq是你本次登陆的QQ令牌,是登陆成功的依据,一定要保存下来

 

到这里你会发现PCQQ通知你:你的QQ在别处登陆,你被迫下线了。有木有很高兴呢(*゚∇゚)

但是你马上会发现,过半分钟你的webqq就掉线啦゚(つд`゚),所以请往下看

 

 

请求说明:

 

请求地址:http://d.web2.qq.com/channel/poll2

Referer:http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=2

POST参数:r:{"ptwebqq":"XXXX","clientid":XXXXX,"psessionid":"XXXXXX","key":""}

以上参数在前次操作中都已经保存。

这是一个poll长轮询,浏览器ajax到服务器,timeout很长,当服务器有你的新消息之后,才把消息返回给你,或者等待很久就给你一个空消息。

服务器知道你还在试图获取新消息,就明白你还在线,即保持在线状态

该次请求返回的消息,即为好友消息或者群消息

 

意识到一个问题:我之前试着按照流程一步一步来,现在突然想到,对返回消息的解析,依赖于好友列表和Q群列表的获取。

因此解析部分我暂时延后。

 

到目前为止,已经可以完整的登陆,并保持在线,获取消息

 

下一篇文章将对获取好友列表和Q群列表作分析,以及一些扩展的介绍

 

使用C#模拟http请求可以参考猛戳这里

您有没有对这篇文章感兴趣呢?

[转载]一步一步来做WebQQ机器人-(二)(第一次登陆) - 上位者的怜悯 - 博客园

mikel阅读(882)

[转载]一步一步来做WebQQ机器人-(二)(第一次登陆) – 上位者的怜悯 – 博客园.

预计会有这些步骤,当然某些步骤可能会合并:

  • 验证码
  • 第一次登陆
  • 第二次登陆
  • 保持在线和接收消息
  • 获取好友和群列表
  • 发送消息
  • 变成智能的(*゚∀゚*)

webqq的登陆,分为2步,本文主要讲第一次登陆

截止到现在,加密方式是这样的:

var hexcase = 1;
var b64pad = "";
var chrsz = 8;
var mode = 32;
function md5(A) {
return hex_md5(A)
}
function hex_md5(A) {
return binl2hex(core_md5(str2binl(A), A.length * chrsz))
}
function str_md5(A) {
return binl2str(core_md5(str2binl(A), A.length * chrsz))
}
function hex_hmac_md5(A, B) {
return binl2hex(core_hmac_md5(A, B))
}
function b64_hmac_md5(A, B) {
return binl2b64(core_hmac_md5(A, B))
}
function str_hmac_md5(A, B) {
return binl2str(core_hmac_md5(A, B))
}
function core_md5(K, F) {
K[F &gt;&gt; 5] |= 128 &lt;&lt; ((F) % 32); K[(((F + 64) &gt;&gt;&gt; 9) &lt;&lt; 4) + 14] = F;
var J = 1732584193;
var I = -271733879;
var H = -1732584194;
var G = 271733878;
for (var C = 0; C &lt; K.length; C += 16) { var E = J; var D = I; var B = H; var A = G; J = md5_ff(J, I, H, G, K[C + 0], 7, -680876936); G = md5_ff(G, J, I, H, K[C + 1], 12, -389564586); H = md5_ff(H, G, J, I, K[C + 2], 17, 606105819); I = md5_ff(I, H, G, J, K[C + 3], 22, -1044525330); J = md5_ff(J, I, H, G, K[C + 4], 7, -176418897); G = md5_ff(G, J, I, H, K[C + 5], 12, 1200080426); H = md5_ff(H, G, J, I, K[C + 6], 17, -1473231341); I = md5_ff(I, H, G, J, K[C + 7], 22, -45705983); J = md5_ff(J, I, H, G, K[C + 8], 7, 1770035416); G = md5_ff(G, J, I, H, K[C + 9], 12, -1958414417); H = md5_ff(H, G, J, I, K[C + 10], 17, -42063); I = md5_ff(I, H, G, J, K[C + 11], 22, -1990404162); J = md5_ff(J, I, H, G, K[C + 12], 7, 1804603682); G = md5_ff(G, J, I, H, K[C + 13], 12, -40341101); H = md5_ff(H, G, J, I, K[C + 14], 17, -1502002290); I = md5_ff(I, H, G, J, K[C + 15], 22, 1236535329); J = md5_gg(J, I, H, G, K[C + 1], 5, -165796510); G = md5_gg(G, J, I, H, K[C + 6], 9, -1069501632); H = md5_gg(H, G, J, I, K[C + 11], 14, 643717713); I = md5_gg(I, H, G, J, K[C + 0], 20, -373897302); J = md5_gg(J, I, H, G, K[C + 5], 5, -701558691); G = md5_gg(G, J, I, H, K[C + 10], 9, 38016083); H = md5_gg(H, G, J, I, K[C + 15], 14, -660478335); I = md5_gg(I, H, G, J, K[C + 4], 20, -405537848); J = md5_gg(J, I, H, G, K[C + 9], 5, 568446438); G = md5_gg(G, J, I, H, K[C + 14], 9, -1019803690); H = md5_gg(H, G, J, I, K[C + 3], 14, -187363961); I = md5_gg(I, H, G, J, K[C + 8], 20, 1163531501); J = md5_gg(J, I, H, G, K[C + 13], 5, -1444681467); G = md5_gg(G, J, I, H, K[C + 2], 9, -51403784); H = md5_gg(H, G, J, I, K[C + 7], 14, 1735328473); I = md5_gg(I, H, G, J, K[C + 12], 20, -1926607734); J = md5_hh(J, I, H, G, K[C + 5], 4, -378558); G = md5_hh(G, J, I, H, K[C + 8], 11, -2022574463); H = md5_hh(H, G, J, I, K[C + 11], 16, 1839030562); I = md5_hh(I, H, G, J, K[C + 14], 23, -35309556); J = md5_hh(J, I, H, G, K[C + 1], 4, -1530992060); G = md5_hh(G, J, I, H, K[C + 4], 11, 1272893353); H = md5_hh(H, G, J, I, K[C + 7], 16, -155497632); I = md5_hh(I, H, G, J, K[C + 10], 23, -1094730640); J = md5_hh(J, I, H, G, K[C + 13], 4, 681279174); G = md5_hh(G, J, I, H, K[C + 0], 11, -358537222); H = md5_hh(H, G, J, I, K[C + 3], 16, -722521979); I = md5_hh(I, H, G, J, K[C + 6], 23, 76029189); J = md5_hh(J, I, H, G, K[C + 9], 4, -640364487); G = md5_hh(G, J, I, H, K[C + 12], 11, -421815835); H = md5_hh(H, G, J, I, K[C + 15], 16, 530742520); I = md5_hh(I, H, G, J, K[C + 2], 23, -995338651); J = md5_ii(J, I, H, G, K[C + 0], 6, -198630844); G = md5_ii(G, J, I, H, K[C + 7], 10, 1126891415); H = md5_ii(H, G, J, I, K[C + 14], 15, -1416354905); I = md5_ii(I, H, G, J, K[C + 5], 21, -57434055); J = md5_ii(J, I, H, G, K[C + 12], 6, 1700485571); G = md5_ii(G, J, I, H, K[C + 3], 10, -1894986606); H = md5_ii(H, G, J, I, K[C + 10], 15, -1051523); I = md5_ii(I, H, G, J, K[C + 1], 21, -2054922799); J = md5_ii(J, I, H, G, K[C + 8], 6, 1873313359); G = md5_ii(G, J, I, H, K[C + 15], 10, -30611744); H = md5_ii(H, G, J, I, K[C + 6], 15, -1560198380); I = md5_ii(I, H, G, J, K[C + 13], 21, 1309151649); J = md5_ii(J, I, H, G, K[C + 4], 6, -145523070); G = md5_ii(G, J, I, H, K[C + 11], 10, -1120210379); H = md5_ii(H, G, J, I, K[C + 2], 15, 718787259); I = md5_ii(I, H, G, J, K[C + 9], 21, -343485551); J = safe_add(J, E); I = safe_add(I, D); H = safe_add(H, B); G = safe_add(G, A) } if (mode == 16) { return Array(I, H) } else { return Array(J, I, H, G) } } function md5_cmn(F, C, B, A, E, D) { return safe_add(bit_rol(safe_add(safe_add(C, F), safe_add(A, D)), E), B) } function md5_ff(C, B, G, F, A, E, D) { return md5_cmn((B &amp; G) | ((~B) &amp; F), C, B, A, E, D) } function md5_gg(C, B, G, F, A, E, D) { return md5_cmn((B &amp; F) | (G &amp; (~F)), C, B, A, E, D) } function md5_hh(C, B, G, F, A, E, D) { return md5_cmn(B ^ G ^ F, C, B, A, E, D) } function md5_ii(C, B, G, F, A, E, D) { return md5_cmn(G ^ (B | (~F)), C, B, A, E, D) } function core_hmac_md5(C, F) { var E = str2binl(C); if (E.length &gt; 16) {
E = core_md5(E, C.length * chrsz)
}
var A = Array(16),
D = Array(16);
for (var B = 0; B &lt; 16; B++) { A[B] = E[B] ^ 909522486; D[B] = E[B] ^ 1549556828 } var G = core_md5(A.concat(str2binl(F)), 512 + F.length * chrsz); return core_md5(D.concat(G), 512 + 128) } function safe_add(A, D) { var C = (A &amp; 65535) + (D &amp; 65535); var B = (A &gt;&gt; 16) + (D &gt;&gt; 16) + (C &gt;&gt; 16);
return (B &lt;&lt; 16) | (C &amp; 65535)
}
function bit_rol(A, B) {
return (A &lt;&lt; B) | (A &gt;&gt;&gt; (32 - B))
}
function str2binl(D) {
var C = Array();
var A = (1 &lt;&lt; chrsz) - 1;
for (var B = 0; B &lt; D.length * chrsz; B += chrsz) { C[B &gt;&gt; 5] |= (D.charCodeAt(B / chrsz) &amp; A) &lt;&lt; (B % 32)
}
return C
}
function binl2str(C) {
var D = "";
var A = (1 &lt;&lt; chrsz) - 1;
for (var B = 0; B &lt; C.length * 32; B += chrsz) { D += String.fromCharCode((C[B &gt;&gt; 5] &gt;&gt;&gt; (B % 32)) &amp; A)
}
return D
}
function binl2hex(C) {
var B = hexcase ? "0123456789ABCDEF": "0123456789abcdef";
var D = "";
for (var A = 0; A &lt; C.length * 4; A++) { D += B.charAt((C[A &gt;&gt; 2] &gt;&gt; ((A % 4) * 8 + 4)) &amp; 15) + B.charAt((C[A &gt;&gt; 2] &gt;&gt; ((A % 4) * 8)) &amp; 15)
}
return D
}
function binl2b64(D) {
var C = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var F = "";
for (var B = 0; B &lt; D.length * 4; B += 3) { var E = (((D[B &gt;&gt; 2] &gt;&gt; 8 * (B % 4)) &amp; 255) &lt;&lt; 16) | (((D[B + 1 &gt;&gt; 2] &gt;&gt; 8 * ((B + 1) % 4)) &amp; 255) &lt;&lt; 8) | ((D[B + 2 &gt;&gt; 2] &gt;&gt; 8 * ((B + 2) % 4)) &amp; 255);
for (var A = 0; A &lt; 4; A++) { if (B * 8 + A * 6 &gt; D.length * 32) {
F += b64pad
} else {
F += C.charAt((E &gt;&gt; 6 * (3 - A)) &amp; 63)
}
}
}
return F
}
function hexchar2bin(str) {
var arr = [];
for (var i = 0; i &lt; str.length; i = i + 2) {
arr.push("\\x" + str.substr(i, 2))
}
arr = arr.join("");
eval("var temp = '" + arr + "'");
return temp
}
function QXWEncodePwd(pt_uin, p, vc) {
var I = hexchar2bin(md5(p));
var H = md5(I + TTescapechar2bin(pt_uin));
var G = md5(H + vc.toUpperCase());
return G
}
function TTescapechar2bin(str) {
eval("var temp = '" + str + "'");
return temp
}

调用方式:

执行QXWEncodePwd方法,传入3个参数QQ号16进制密码验证码

 

我当时也找了很久资料,请教了不少前辈,确实得到不少方法可以在C#中执行js代码

但是有一个大问题没有解决:XP我已经放弃了,但是在32,64的win7,win8中,找不到能够兼容所有的方式…

如果有人知道了请告诉我,谢谢。目前没有win8,64位的方法

最后的解决方式是Webbrowser,虽然这样丑了点,但是确实可以兼容所有

 

 

这里是GET的地址:string.Format("https://ssl.ptlogin2.qq.com/login?u={0}&p={1}&verifycode={2}&webqq_type=10&remember_uin=1&login2qq=1&aid=501004106&u1=http%3A%2F%2Fw.qq.com%2Fproxy.html%3Flogin2qq%3D1%26webqq_type%3D10&h=1&ptredirect=0&ptlang=2052&daid=164&from_ui=1&pttype=1&dumy=&fp=loginerroralert&action=0-28-696051&mibao_css=m_webqq&t=2&g=1&js_type=0&js_ver=10095&login_sig=a9NQ-9*PnzKFxzP7jcE7voRx5Z9x6Khffy44FKhIkaD-n8fShtaK1r1GZRjgsxzA&pt_vcode_v1=0&pt_verifysession_v1={3}", this.QQNum, p, this.CodeString, this.VerifySession);

 

一共有3个参数会在GET的URL里面用到:

QQ号码、刚刚得到的加密密文、上篇文章里面保存的verifysession

 

会返回如下数据:

 

如:ptuiCB('0','0','http://ptlogin4.web2.qq.com /check_sig?pttype=1&uin=2835049203&service=login&nodirect=0& amp;ptsigx=6ed07693d2f686011fdc5d80a4ad1ab1292b00816cad7f21ad59f8340488f2a591bb79b0759de037d54026803ff4e4f8f3ca61dbbcf8e3dc77cad4e2cbfbff58& amp;s_url=http%3A%2F %2Fw.qq.com%2Fproxy.html%3Flogin2qq%3D1%26webqq_type%3D10&f_url=& amp;ptlang=2052&ptredirect=100&aid=501004106&daid=164& j_later=0&low_login_hour=0&regmaster=0&pt_login_type=1& pt_aid=0&pt_aaid=0&pt_light=0','0','登录成功!', '嘴角的弧度');

可以得到6个参数,分别是:

是否成功(0表示没有问题)未知一个地址(需要保存)未知提示信息(包含所有登录情况)昵称

1.在本次请求之后,获取本次请求的CookieCollection,遍历得到name为”ptwebqq”的cookie的值,保存下来

2.从请求返回的数据中,刚刚提到的第3个参数(一个地址),这个地址GET一次,更新cookie保存


 

 

到目前为止,已经进行了第一次登陆,验证了密码并保存了Cookie,并获取了一些参数

下一篇文章将对最终的真正登陆(可以将QQ挤下来),和保持在线(poll长轮询)作描述

使用C#模拟http请求可以参考猛戳这里

您有没有对这篇文章感兴趣呢?

[转载]一步一步来做WebQQ机器人-(一)(验证码) - 上位者的怜悯 - 博客园

mikel阅读(1204)

[转载]一步一步来做WebQQ机器人-(一)(验证码) – 上位者的怜悯 – 博客园.

Well done! 为了探究webqq的http请求流程和数据交互,我付出了很多心血。

写下这篇文章!!!这是我逝去的青春

系列写完之后我会把源码打包奉上~

——我的征途是星辰大海

 

预计会有这些步骤,当然某些步骤可能会合并:

  • 验证码
  • 第一次登陆
  • 第二次登陆
  • 保持在线和接收消息
  • 获取好友和群列表
  • 发送消息
  • 变成智能的(*゚∀゚*)

 

对这个页面先get一次,保存下cookie

 

 

在用户输入完QQ号之后,会触发一个http请求,用来检测该账号是否需要验证码。

请求地址: “https://ssl.ptlogin2.qq.com/check?uin=” + QQNum + “&appid=501004106&js_ver=10095&js_type=0&login_sig=a9NQ-9*PnzKFxzP7jcE7voRx5Z9x6Khffy44FKhIkaD-n8fShtaK1r1GZRjgsxzA&u1=http%3A%2F%2Fw.qq.com%2Fproxy.html&r=0.6158497643191367”;

 

 

分析:1.这里是使用了jsonp的方式,对QQ号码的安全性进行了检测

2.本图的操作不需要验证码校验

3.方法内前4个参数用得到:

  • 1表示需要验证码,0则表示QQ号码安全
  • 第二个参数表示验证码,QQ安全表示你不用自己输入验证码,TX会帮你后台生成验证码…
  • QQ号码16进制
  • verifysession,后文用得到,先保存下来

 

 

 

分析:1.这里是使用了jsonp的方式,对QQ号码的安全性进行了检测

2.本图的操作需要验证码校验(多次反复登陆,IP异常等)

3.这次返回的参数只有第一个用得到,1表示需要验证码,0则表示QQ号码安全

 

 

1.请求的地址:”https://ssl.captcha.qq.com/getimage?aid=501004106&r=0.8478438374586403&uin=” + QQNum;

2.请求需要带上referer:”https://ui.ptlogin2.qq.com/cgi-bin/login?daid=164& amp;target=self&style=16&mibao_css=m_webqq&appid=501004106&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fw.qq.com%2Fproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20131024001″;

3.获取图片后,需要保存该次请求的cookie

4.从cookie中找到”verifysession”的值,保存下来

 

 


 

很好!已经完成了登陆前的准备

使用C#模拟http请求可以参考猛戳这里

博主毕业半年多了,才找到一份工作,做外包每天很累,晚上尽量抽出时间来完善这个系列,请各位多关注~

您有没有对这篇文章感兴趣呢?

 

[转载]Asp.net Mvc问题索引 - 重典 - 博客园

mikel阅读(825)

[转载]Asp.net Mvc问题索引 – 重典 – 博客园.

这篇文章是对我以及朋友们学习ASP.NET Mvc遇到的问题的一个总结,将我们发现并解决的问题列出来,希望大家回复补充。

 

  1. 用Html.Form生成表单:http://forums.asp.net/t/1327536.aspx
  2. 为Helper添加事件:类似下面即可
    //chsword 重典
        
        <%= Html.DropDownList( "ddlStats", new { onchange, "changed();" } ) %>
  3. DropDownList初始化:http://forums.asp.net/t/1321344.aspx
  4. RenderPartial为什么语法错误:它的使用方法是
    //chsword 重典
        <% Html.RenderPartial("viewname");%>
  5. 连接输出QueryString问题如/html/index?a=b&c=d
    //chsword 重典
        Html.ActionLink("xxx","Index","Home",new{a="b",c="d"},null)
  6. Html.之后无智能感知:可能是没编译或建的不是ASP.NET mvc的Page
  7. Asp.net 不显示中文的解决方法:http://www.eice.com.cn/bbs/showtopic-100.aspx
  8. ReadFromRequest不存在的问题:Pv5之后已经去除请用Request.Form/Param/Request.QueryString读取
  9. Controller中生成URL(根据Controller和View):http://code.google.com/p/mvccontrib/source/browse/trunk/src/MVCContrib/UI/BlockRenderer.cs http://www.cnblogs.com/chsword/archive/2008/08/06/dotnetmvcframework_controlleraction.html
  10. 繁杂绑定:http://forums.asp.net/t/1329386.aspx
  11. 不想用Session来存TempData:http://www.cnblogs.com/QLeelulu/archive/2008/09/19/1294469.html
  12. 为filter添加日志:http://www.cnblogs.com/AndersLiu/archive/2008/08/26/logging-with-aspnet-mvc-fction-filters.html
  13. 将/home/index重写为/index:http://forums.asp.net/t/1326487.aspx
  14. 使用FCKEditor:http://forums.asp.net/t/1312846.aspx
  15. 使用JQueryhttp://www.sethjuarez.com/post/2008/06/Using-JQuery-to-perform-Ajax-calls-in-ASPNET-MVC.aspx
  16. .net2.0sp1/IIS6下运行:http://www.cnblogs.com/chsword/archive/2008/08/06/dotnetmvcframeworknet2_0.html