zoukankan      html  css  js  c++  java
  • mongodb 多表关联处理 : 内嵌以及连接(手动引用、DBref) 、aggregate中$lookup

    MongoDB与关系型数据库的建模还是有许多不同,因为MongoDB支持内嵌对象和数组类型。MongoDB建模有两种方式,一种是内嵌(Embed),另一种是连接(Link)。那么何时Embed何时Link呢?那得看两个实体之间的关系是什么类型。

    一对一的关系:Embed,比如用户信息集合有Address字段,Address字段有省、市、县三个字段。建模如下:

    QQ截图20120725190049

    QQ截图20120725185306

    一对多关系:一篇文章有多条评论,为1对多关系

    QQ截图20120725185727QQ截图20120725190617

    由于MongoDB对单个文档(document)有大小限制16M(高于v1.8),设计时也要将这个限制纳入考虑中。

    多对多关系:学生和课程是多对多的关系,一个学生可以选多门课程,一门课程有多名学生参与。

    QQ截图20120725190110

    多对多使用了连接(Linking),连接是通过引用(References)来连接两个集合。MongoDB References有两种:一种是 手动引用(Manual References),另一种是DBRefs。

    Manual References:

    QQ截图20120725192451(user集合)

    QQ截图20120725192634(post集合)

    红框地方就是Manual References,如果想查询一篇文章的作者信息,首先在post集合找出那篇文章,然后在user集合查找出用户的全部信息。但是假如有这么一个场景:用户可以对图片,文章等各种资源评论,所有的评论都放在comment集合中,如果只是使用Manual References,就分不清楚评论到底是属于哪类资源了,图片?文章?。所以有了DBRef。

    DBRef的形式:

    { $ref : <value>, $id : <value>, $db : <value> }
    $ref:集合名称;$id:引用的id;$db:数据库名称,可选参数。
    可以看到DBRef的结构比Manual References的复杂,占用的空间大,但是功能也强大,如果要跨数据库连接,上面讲的评论集合的例子,都得需要使用DBRef,MongoDB提供了函数来解析DBRef,不用像Manual References需要自己手动写两次查询。
    QQ截图20120725195916
     
    关于MongoDB的数据建模MongoDB官网也给出了一些建议。这些建议都是提供了一些参考,实际建模需要根据具体的需求来分析,
    分析数据经常会执行哪些操作(排序,查找,修改)来选择Embed和Link。

    ---------

      我们来看mongodb另一个非常有意思的东西,那就是$lookup,我们知道mongodb是一个文档型的数据库,而且它也是最像关系型数据库的

    一种nosql,但是呢,既然mongodb是无模式的,自然就很难在关系型数据库中非常擅长的多表关联上发挥作用,在这之前,我们可以使用DbRef,但

    是呢,在mongodb 3.2 中给你增加了一个相当牛逼的手段,那就是$lookup,而且放到了aggreation这种重量级的pipeline分析框架上,自然就是一等

    公民了,牛逼哈~。

    $lookup:

    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()


    语法:
    db.product.aggregate([ { $lookup: { from: "orders", localField: "_id", foreignField: "pid", as: "inventory_docs" } } ])
    然后展示的结果如下:
    复制代码
     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:           对应的外键集合的数据,【因为可能是一对多的,对吧】

    参考文档:http://www.cnblogs.com/huangxincheng/p/5728791.html

          http://blog.csdn.net/bugall/article/details/45062663

    
    
  • 相关阅读:
    程序格式
    java数据类型
    java-helloworld
    原生字符串
    字符串常见操作19个操作
    字符串函数操作
    【字符串切片操作和range函数用法】
    【字符串拼接之两种方法】
    C#中ref和out的区别使用
    c语言内部函数、外部函数多文件编译总结(vs2015编译环境)
  • 原文地址:https://www.cnblogs.com/GtShare/p/7736603.html
Copyright © 2011-2022 走看看