mongodb 3.x 之实用新功能窥看[2] ——使用$lookup做多表关联处理
这篇我们来看mongodb另一个非常有意思的东西,那就是$lookup,我们知道mongodb是一个文档型的数据库,而且它也是最像关系型数据库的
一种nosql,但是呢,既然mongodb是无模式的,自然就很难在关系型数据库中非常擅长的多表关联上发挥作用,在这之前,我们可以使用DbRef,但
是呢,在mongodb 3.2 中给你增加了一个相当牛逼的手段,那就是$lookup,而且放到了aggreation这种重量级的pipeline分析框架上,自然就是一等
公民了,牛逼哈~。
一:介绍Aggregate
这个aggregate在mongodb中算是一个非常重量级的工具了,而且pipeline的管道模型的理论就是后面操作的数据源来源于上一次操作的结果,这个
应该很好理解吧,好了,下面我们简单看看aggreation中到底有哪几个一等公民。
很简单,就是上面的这十三个,比如说有了所谓的$group操作,我们就可以把这个aggreation做group的处理,有了$sort操作,就可以将结果进行排
序,有了$out操作,我们就可以将结果放到一个collections中去或者inline模式展示。。。
1. $lookup
说了这么多,下面我们简单的来演示一下,比如我们有一个product表,有一个orders表,自然就存在着一个外键关系,下面我们就来造点数据。
db.product.insert({"_id":1,"productname":"商品1","price":15}) db.product.insert({"_id":2,"productname":"商品2","price":36}) db.orders.insert({"_id":1,"pid":1,"ordername":"订单1"}) db.orders.insert({"_id":2,"pid":2,"ordername":"订单2"}) db.orders.insert({"_id":3,"pid":2,"ordername":"订单3"}) db.orders.insert({"_id":4,"pid":1,"ordername":"订单4"}) db.product.find() db.orders.find()
好了,数据已经构造完毕,接下来我们要做的一个小需求就是,在orders表中,找到price of product >20 的订单,这个需求看起来很简单,对吧,
但是呢,我们的orders表中是没有price的field的,所以第一步就是:
<1> $lookup 表关联
1 db.product.aggregate([ 2 { 3 $lookup: 4 { 5 from: "orders", 6 localField: "_id", 7 foreignField: "pid", 8 as: "inventory_docs" 9 } 10 } 11 ])
然后展示的结果如下:
1 /* 1 */ 2 { 3 "_id" : 1.0, 4 "productname" : "商品1", 5 "price" : 15.0, 6 "inventory_docs" : [ 7 { 8 "_id" : 1.0, 9 "pid" : 1.0, 10 "ordername" : "订单1" 11 }, 12 { 13 "_id" : 4.0, 14 "pid" : 1.0, 15 "ordername" : "订单4" 16 } 17 ] 18 } 19 20 /* 2 */ 21 { 22 "_id" : 2.0, 23 "productname" : "商品2", 24 "price" : 36.0, 25 "inventory_docs" : [ 26 { 27 "_id" : 2.0, 28 "pid" : 2.0, 29 "ordername" : "订单2" 30 }, 31 { 32 "_id" : 3.0, 33 "pid" : 2.0, 34 "ordername" : "订单3" 35 } 36 ] 37 }
最后我放一张图,这样好眼见为实:
下面我简单介绍一些$lookup中的参数:
from:需要关联的表【orders】
localField: 【product】表需要关联的键。
foreignField:【orders】的matching key。
as: 对应的外键集合的数据,【因为可能是一对多的,对吧】
好了,表关联已经做好了,接下来我们就需要用另外一个关键词叫做$match,where条件的意思嘛。。。
<2> $match筛选
1 db.product.aggregate([ 2 { 3 $lookup: 4 { 5 from: "orders", 6 localField: "_id", 7 foreignField: "pid", 8 as: "inventory_docs" 9 } 10 }, 11 { $match : { price : {$gt:20} } } 12 ])
果然不出所料,我们就把”商品1“过滤掉了,因为它的价格小于20,对吧,但是呢,看起来还不是很完美,应为我只需要orders信息,并不想要
所谓的product 这些属性,这个时候我们就可以使用$project 做select操作了。。。
<3> $project 挑选字段
接下来我们使用$project来指定我要获取的字段,比如我只需要inventory_docs字段就可以了。
ok,当我执行之后,现在是这个吊样子了,这个就是本篇所说的,是不是很简单,同时呢,我也给大家简单的介绍了下Aggreation的使用,是不
是很好玩,当然Aggregate下面还有其他很多的$操作符,你可以按照要求试试看哦~ 记得这个可是pipeline的模式哦。。。