首页 > 代码库 > 第一部分 基础篇 第四章 MongoDB查询

第一部分 基础篇 第四章 MongoDB查询

声明:该文章主要来自《MongoDB实战》一书内容,主要想通过该书学习MongoDB的相应知识,加深理解,故写在自己的博文当中,作为记录,在最后的章节中,会有一个自己集合MongoDB数据库应用的JavaEE的web应用。

1、查询记录

1.1、普通查询

在没有深入查询之前,我们先看看怎么从一个查询中返回一个游标对象,可以简单的通过find()来查询,它返回一个任意结构的集合,如果实现特定的查询在稍后讲解。

实现上面同样的查询,然后通过while来输出:

> var cursor = db.xuz.find();
> while(cursor.hasNext()) printjson(cursor.next());
{ "_id" : ObjectId("54a8a4ff2db3e1b27d0e5203"), "name" : "mongo" }
{ "_id" : ObjectId("54a8a5042db3e1b27d0e5204"), "x" : 4 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2466"), "x" : 5, "j" : 1 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2467"), "x" : 5, "j" : 2 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2468"), "x" : 5, "j" : 3 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2469"), "x" : 5, "j" : 4 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246a"), "x" : 5, "j" : 5 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246b"), "x" : 5, "j" : 6 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246c"), "x" : 5, "j" : 7 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246d"), "x" : 5, "j" : 8 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246e"), "x" : 5, "j" : 9 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246f"), "x" : 5, "j" : 10 }

上面的例子显示了游标风格的迭代输出,.hasNext()函数告诉我们是否还有数据,如果有则可以调用next()函数。

当我们使用的是JavaScript shell,可以用到JS的特性,forEach就可以输出游标了,下面的例子就是使用forEach()来循环输出:forEach()必须定义一个函数供每个游标元素调用。

> db.xuz.find().forEach(printjson)
{ "_id" : ObjectId("54a8a4ff2db3e1b27d0e5203"), "name" : "mongo" }
{ "_id" : ObjectId("54a8a5042db3e1b27d0e5204"), "x" : 4 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2466"), "x" : 5, "j" : 1 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2467"), "x" : 5, "j" : 2 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2468"), "x" : 5, "j" : 3 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2469"), "x" : 5, "j" : 4 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246a"), "x" : 5, "j" : 5 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246b"), "x" : 5, "j" : 6 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246c"), "x" : 5, "j" : 7 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246d"), "x" : 5, "j" : 8 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246e"), "x" : 5, "j" : 9 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246f"), "x" : 5, "j" : 10 }

在MongoDB shell里,我们也可以把游标当做数组来使用:

> var cursor = db.xuz.find();
> printjson(cursor[4]);
{ "_id" : ObjectId("54a8a5a427681683ca2c2468"), "x" : 5, "j" : 3 }

使用游标时候请注意占用内存的问题,特别是很大的游标对象,有可能会内存溢出,所以以你更改用迭代的方式来输出,下面的实例则是把游标转换成真实的数组类型:

> var arr = db.xuz.find().toArray();
> arr[4];
{ "_id" : ObjectId("54a8a5a427681683ca2c2468"), "x" : 5, "j" : 3 }

请注意这些特性只是在Mongo Shell里使用,而不是所有的其他应用程序驱动都支持,MongoDB游标对象不是没有快照,如果有其他用户在集合里第一次或者最后一次调用next(),你可能得不到游标里的数据,所以要明确的锁定你要查询的游标。


1.2、条件查询

到这里我们已经知道怎么从游标里实现一个查询并返回数据对象,下面就来看看怎么根据指定的条件来查询。

下面的实例就是说明如何执行一个类似SQL的查询,并演示了怎么在MongoDB里实现,这是在MongoDB shell里查询,当然你也可以用其他的应用程序驱动或者语言来实现:

SQL:select * from xuz where name="mongo";

MongoDB:

> db.xuz.find({name:"mongo"}).forEach(printjson);
{ "_id" : ObjectId("54a8a4ff2db3e1b27d0e5203"), "name" : "mongo" }

SQL:select * from xuz where x=4

MongoDB:

> db.xuz.find({x:4}).forEach(printjson);
{ "_id" : ObjectId("54a8a5042db3e1b27d0e5204"), "x" : 4 }

查询条件是{a:A,b:B,....}类似于where a==A and b==B and ....

上面显示的是所有的元素,当然我们也可以返回特定的元素,类似于返回表里某个字段的值,只需要在find({x:4})里指定元素的名字。

SQL:select j from xuz where x=4

MongoDB:

> db.xuz.find({x:5},{j:true}).forEach(printjson);
{ "_id" : ObjectId("54a8a5a427681683ca2c2466"), "j" : 1 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2467"), "j" : 2 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2468"), "j" : 3 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2469"), "j" : 4 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246a"), "j" : 5 }

1.3、findOne()语法

为了方便考虑,MongoDB shell避免游标可能带来的开销,提供一个findOne()函数,这个函数和find()函数一样,不过它返回的是游标里第一条数据,或者返回null,即空数据。

作为一个例子,name="mongo"可以用很多方法来实现,可以用next()来循环游标或者当做数组返回第一个元素。

但是用findOne()方法则更简单和高效:

> printjson(db.xuz.findOne({name:"mongo"}))
{ "_id" : ObjectId("54a8a4ff2db3e1b27d0e5203"), "name" : "mongo" }


1.4、通过limit限制结果集数量

如果需要限制结果集的长度,那么可以调用limit方法

这是强烈推荐解决性能问题的额方法,就是通过限制条数来减少网络传输,比如:

> db.xuz.find().limit(3)
{ "_id" : ObjectId("54a8a4ff2db3e1b27d0e5203"), "name" : "mongo" }
{ "_id" : ObjectId("54a8a5042db3e1b27d0e5204"), "x" : 4 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2466"), "x" : 5, "j" : 1 }
> db.xuz.find().count();
63

通过上面可以知道,xuz集合中总共有63条数据,然后设定limit的值之后只查询出3条数据,limit也是分页查询常用到。


2、修改记录

将name是mongo的记录的name修改为mongo_new。

> db.xuz.update({name:"mongo"},{$set:{name:"mongo_new"}});
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.xuz.find();
{ "_id" : ObjectId("54a8a4ff2db3e1b27d0e5203"), "name" : "mongo_new" }


3、删除记录

将用户name是mongo_new的记录从集合xuz中删除。

> db.xuz.remove({name:"mongo_new"});
WriteResult({ "nRemoved" : 1 })
> db.xuz.find();
{ "_id" : ObjectId("54a8a5042db3e1b27d0e5204"), "x" : 4 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2466"), "x" : 5, "j" : 1 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2467"), "x" : 5, "j" : 2 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2468"), "x" : 5, "j" : 3 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2469"), "x" : 5, "j" : 4 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246a"), "x" : 5, "j" : 5 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246b"), "x" : 5, "j" : 6 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246c"), "x" : 5, "j" : 7 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246d"), "x" : 5, "j" : 8 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246e"), "x" : 5, "j" : 9 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246f"), "x" : 5, "j" : 10 }

经验证却是没有name为mongo_new的记录了。


4、常用工具集

MongoDB在bin目录下提供了一系列有用的工具,这些工具提供了MongoDB在运维管理上的方便。

  • bsondump:将bson格式的文件转存为json格式的数据。
  • mongo:客户端命令行工具,其实也是一个JS解释器,支持JS语法
  • mongod:数据库服务端,每个实例启动一个进程,可以fork为后台运行。
  • mongodump/mongorestore:数据备份和恢复工具。
  • mongoexport/mongoimport:数据导出和导入工具。
  • mongofile:GridFS管理工具,可实现二进制文件的存取。
  • mongos:分片路由,如果使用了sharding功能,则应用程序连接的是mongos而不是mongod。
  • mongostat:实时性能监控工具。
  • mongotop:提供每个集合的水平的统计数据。
以上所有工具在以后的章节中会详细的介绍到。

第一部分 基础篇 第四章 MongoDB查询