如何具体解决mongodb查询中没有join操作


  • 註冊用戶

    最近自学Mongodb,发现其在进行数据查询时不能像sqlserver 一样灵活使用join连接查询,看到书上提到由于mongodb的字段数据类型可以嵌套,数据类型可为数组等多种复杂的结构模型,针对字段类型为数组的查询,提供了一些特殊的查询方式。想请教有经验的前辈,能否具体说明一下这所谓的特殊的查询方式,谢谢~~~~~


  • 註冊用戶

    我也有相同的問題待解決


  • Lv 1

    MongoDB本身沒有提供join的功能,可以在mongo shell使用javascript去實現,只是資料量一大,效能就不是很好

    db.collection1.find().forEach(
         function(doc){
               data=db.collection2.find({_id:doc._id}).toArray();
    )

  • 註冊用戶

    mongodb是不支持join操作的,因此我们只能自己来实现这个功能

      collection A 的数据格式:

    { "_id" : { "username" : "jifeng.zjd", "version" : 2 }, "value" : 1 }

         collection B 的数据格式:

    { "user_id" : 12630, "username" : "jifeng.zjd" }

    可以先取出A表的所有数据,然后去B表查询,看那些数据同时存在于A和B表中。当然在mongodb中对A和B建立适当的索引是非常必要的。

    大概的概念是這樣,可以參考這篇文章 

    本帖下載内容已隐藏,请登入以查看隐藏内容!
     


  • 註冊用戶

    @Amber感谢回答,目前自己用js实践是可以解决简单问题😊


  • 註冊用戶

    @JasonChen 谢谢你,这个回答比较详细,参看原文更理解了一些😊


  • 註冊用戶

    你可以試試 $lookup

    https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/


  • 註冊用戶

    @Amber

    資料總筆數應該是1.7559529E7這麼多。會再持續增大.

    裡面可能有幾個欄位.我們假設是使用者id/帳號.數量大約是160168

    除了用javascript的方法實現.還有其他的方式嗎?

    用javascript效能真的不是太好


  • 註冊用戶

    就目前我使用起來,也只能用4樓的方法,會比較快些,真希望 MongoDB能優化這部分

    數據資料也不能說完全不 Join,尤其是既有系統轉化為 MongoDB的時候

    假使是新系統,或許還有機會設計新的資料結構,來符合 MongoDB的特性

    不然真的是沒有辦法


  • Lv 1

    剛看到這篇, 轉貼不錯使用方式:

    在MongoDB中使用JOIN操作

    SQL与NoSQL最大的不同之一就是不支持JOIN,在传统的数据库中,SQL JOIN子句允许你使用普通的字段,在两个或者是更多表中的组合表中的每行数据。例如,如果你有表bookspublishers,你可以像下面这样写命令:

    SELECT book.title, publisher.name
    FROM book
    LEFT JOIN book.publisher_id ON publisher.id;

    换句话说,book表中的publisher_id字段引用了publishers表中的id字典。这些都是很常见的例子:对于每个<code>publisher都可以拥有成千上万本书,如果你想更新<code>publisher的信息的时候,我们只需要更改一条记录。数据的冗余是很小的,因为我们不需要为每本书来重复更新他的publisher信息,这种技术已基本当做一种规范化的东西了。SQL数据库提供了一些列的规范与约束条件来保障数据关联性。

    NoSQL == No JOIN?

    并不都是这样吧。。。。。

     

    面向文档的数据库,例如MongoDB,被设计用来存储非结构化的数据,理想情况下,这些数据是在数据集合中是相互没有关联的,如果一条数据包含两次或者更多次,那数据就重复了。因为大部分情况下我们还是需要数据关联的,只有很少的情况下才会不需要关联数据,

    ,看来NoSQL这些特性看来让人失望啊。幸运的是MongoDB 3.2 介绍了一个新的$lookup操作,这个操作可以提供一个类似于LEFT OUTER JOIN的操作在两个或者是更多的条件下。

    MongoDB Aggregation

    $lookup仅仅在 操作中才被允许使用,想想他作为一个管道操作:查询,过滤,组合结果。一个操作的输出被作为下一个的输入。Aggregation比简单的查询操作更难于理解,而且这些操作通常运行很慢,然而他们很高效,Aggregation可以使用一个很好的例子来解释,假设我们使用user数据集合来创建一个社交平台,在每个独立的文档中存储没个用户的信息,例如:

    {
      "_id": ObjectID("45b83bda421238c76f5c1969"),
      "name": "User One",
      "email: "",
      "country": "UK",
      "dob": ISODate("1999-09-13T00:00:00.000Z")
    }

    我们可以向user这个集合中添加足够多的用户,但是每个MongoDB文档都必须有一个为一个_id字段值,这个_id字段值就像SQL中的键,在我们没有明确指定_id的时候会被自动的加入到文档中。我们的社交网站现在需要一个post集合,这个结合存储用户的评论,这个文档存储纯文本,时间,评分,一个被写到user_id字段的玩家引用。

    {
      "_id": ObjectID("17c9812acff9ac0bba018cc1"),
      "user_id": ObjectID("45b83bda421238c76f5c1969"),
      "date: ISODate("2016-09-05T03:05:00.123Z"),
      "text": "My life story so far",
      "rating": "important"
    }

    我们现在想要显示最近具有important评论的二十条数据,这些数据来自所有的用户,并且是按照时间排序的。每一个返回的文档中应该包含评论的文本,发布评论的时间,以及相关的用户的名字和国家。

    MongoDB数据库的查询是通过传递管道操作的数组,这个数组中顺序的定了每个操作。首先,我们需要从所有的post集合中提取出所有的文档,这些文档使用$match记性准确rating过滤。

    { "$match": { "rating": "important" } }

    我们现在需要对过滤出来的文档按照时间,使用$sort操作进行排序。

    { "$sort": { "date": -1 } }

    因为我们要仅仅返回二十条数据,我们可以使用$limit来限制我们需要处理的文档数量。

    { "$limit": 20 }

    我们现在使用$lookup操作从user集合中连接数据,这个操作需要一个四个参数的对象:

    1、localField:在输入文档中的查找字段

    2、from:需要连接的集合

    3、foreignField:需要在from集合中查找的字段

    4、as:输出的字段名字

    所以我们的操作是这样的:

    { "$lookup": {
      "localField": "user_id",
      "from": "user",
      "foreignField": "_id",
      "as": "userinfo"
    } }

    在我们的输出中将会创建一个名为userinfo的新字段,他是一个数组,其中每个元素都是在user集合中匹配的元素。

    "userinfo": [
      { "name": "User One", ... }
    ]

    在post.user_id与user._id之间,我们具有一对一的关系,因为对于每一个post只有一个用户。因此我们的userinfo数组将会仅仅包含一个元素,我们可以说使用 操作来解构他并插入到一个自文档中。

    { "$unwind": "$userinfo" }

    现在的输出将会转化成更加常用的结构:

    "userinfo": {
      "name": "User One",
      "email: "",
      …
    }

    最终我们可以在管道中使用 操作返回评论信息,评论的时间,评论的用户名,国家等。

    { "$project": {
      "text": 1,
      "date": 1,
      "userinfo.name": 1,
      "userinfo.country": 1
    } }

    合并上面所有的操作

    我们最终的聚合查询匹配的评论,按照顺序排序,限制最新的二十条信息,连接用户的数据,扁平用户数组,最后只返回我们需要的必须数据,总的命令如下:

    db.post.aggregate([
      { "$match": { "rating": "important" } },
      { "$sort": { "date": -1 } },
      { "$limit": 20 },
      { "$lookup": {
        "localField": "user_id",
        "from": "user",
        "foreignField": "_id",
        "as": "userinfo"
      } },
      { "$unwind": "$userinfo" },
      { "$project": {
        "text": 1,
        "date": 1,
        "userinfo.name": 1,
        "userinfo.country": 1
      } }
    ]);

    结果是一个拥有二十个文档的集合,例如:

    [
      {
        "text": "The latest post",
        "date: ISODate("2016-09-27T00:00:00.000Z"),
        "userinfo": {
          "name": "User One",
          "country": "UK"
        }
      },
      {
        "text": "Another post",
        "date: ISODate("2016-09-26T00:00:00.000Z"),
        "userinfo": {
          "name": "User One",
          "country": "UK"
        }
      }
      ...
    ]

    MongoDB的$lookup很好用而且很高效,但是上面这个基础的例子只是一个组合的集合查询。他不是一个对SQL中的更加高效的JOIN子句的替代。而且MongoDB也提供了一些限制,如果user集合被删除了,post文档还是会保留。

    理想情况下,这个$lookup操作应该不会经常使用,如果你需要经常使用它,那么你就使用了错误的数据存储了(数据库):如果你有相关联的数据,应该使用关联数据库(SQL)。

    也就是说$lookup是一个MongoDB 3.2新加入的,他解决了当在Nosql数据库中使用一些小的相关联的数据查询的时候一些令人失望的问题。

    資料來源: 

    本帖下載内容已隐藏,请登入以查看隐藏内容!


登录后回复
 

与 萌阔论坛 的连接断开,我们正在尝试重连,请耐心等待