上一篇文章我们讲述了文档和文档插入相关的内容,本篇我们继续学习MongoDB中关键的查询和聚合功能。基于MongoDB实战-面向文档的数据(找到最合适的数据建模方式)这篇博文中的建立的电子商务模型。本章将讲述基于它进行很多不同的查询,包括_id查询,范围查询,排序和投影(Projection)。除了查询,我们还会涉及聚合(aggregation)主题。查询允许你获得存储的数据,聚合函数则能汇总并重新组织那些数据。还会介绍MongoDB的分组和MapReduce函数。
1. 电子商务查询
MongoDB实战-面向文档的数据这篇博文中,我们给出了电子商务数据模型。我们已经为产品、分类、用户、订单和产品评论定义了文档结构。下面针对这些文档数据进行对应的查询操作。
1.1 产品、分类和评论
大多数电子商务应用程序都提供至少两种基本的产品和分类视图。第一种是产品主页,突出某个指定的产品,显示其评论,给出一些与产品分类相关的信息。第二种是产品列表界面,允许用户浏览分类层级,查询所有分类中所有产品的缩略图。先进入对应的数据库product,use product过后,执行下述指令
product=db.products.findOne({'slug':'wheel-barrow-9092'})
db.categories.findOne({'_id':product['main_cate_id']})
db.review.findOne({'product_id':product['_id']})
执行结果如下:
若将最后的查询换为find方法,执行结果如下:
在使用查询方法时,注意区分find和findOne的区别。find返回的是游标对象;findOne返回的是一个文档,下面的两个查询语句是等价的。
product=db.products.findOne({'slug':'wheel-barrow-9092'})
product=db.products.find({'slug':'wheel-barrow-9092'}).limit(1)
如果仅仅想要一个文档,只要它存在,findOne就能找到它。如果需要返回多个文档,就要使用find方法了,该方法返回一个游标,你需要在应用程序里对它进行迭代。大多数应用程序会对返回结果进行分页。为此MongoDB提供了skip和limit选项,可以像下面这样对评论文档进行分页
db.review.find({'product_id':product['_id']}).skip(0).limit(12)
为了保证review集合中具有足够的文档,使用Ruby批量插入的方式,一次插入了40个文档
require 'mongo'
con=Mongo::Client.new(['127.0.0.1:27017'],:database=>'peoduct')
logInfo=con['review']
docs=(0..40).map do |n|
{
:_id=>BSON::ObjectId.new,
:product_id=>BSON::ObjectId("59884b76b53fab2a8024b6ad"),
:date=>Date.new(2010,5,7),
:title=>"Amazing",
:text=>"Has a squeaky wheel,but still a darn good wheel barrow",
:rating=>4,
:user_id=>BSON::ObjectId("4a5b1476238d3b4dd5000001"),
:user_name=>"dgreenthumb",
:helpful_votes=>n,
:voter_ids=>[
BSON::ObjectId("59884b76b53fab2a8024b600"),
BSON::ObjectId("59884b76b53fab2a8024b601"),
BSON::ObjectId("59884b76b53fab2a8024b602")
],
:time=>Time.now.utc
}
end
logInfo.insert_many(docs)
文档插入后再次执行上述分页查询语句,结果如下:
还有一种应用场景,就是首先查询一个指定的类,然后获取指定类的同级分类,以及该类下的所有产品,完整的程序如下:
category=db.categories.findOne({'slug':'outdoors'})
slibings=db.categories.find({'parent_