【问题标题】:mongodb php - how to do "INNER JOIN"-like querymongodb php - 如何进行类似“INNER JOIN”的查询
【发布时间】:2010-09-30 10:18:19
【问题描述】:

我正在使用 Mongo PHP 扩展。

我的数据如下:

users
{
  "_id": "4ca30369fd0e910ecc000006",
  "login": "user11",
  "pass": "example_pass",
  "date": "2010-09-29"
},
{
  "_id": "4ca30373fd0e910ecc000007",
  "login": "user22",
  "pass": "example_pass",
  "date": "2010-09-29"
}

news
{
  "_id": "4ca305c2fd0e910ecc000003",
  "name": "news 333",
  "content": "news content 3333",
  "user_id": "4ca30373fd0e910ecc000007",
  "date": "2010-09-29"
},
{
  "_id": "4ca305c2fd0e910ecc00000b",
  "name": "news 222",
  "content": "news content 2222",
  "user_id": "4ca30373fd0e910ecc000007",
  "date": "2010-09-29"
},
{
  "_id": "4ca305b5fd0e910ecc00000a",
  "name": "news 111",
  "content": "news content",
  "user_id": "4ca30369fd0e910ecc000006",
  "date": "2010-09-29"
}

如何从 PHP 运行类似这样的查询?

SELECT n.*, u.* 
FROM news AS n 
INNER JOIN users AS u ON n.user_id = u.id

【问题讨论】:

    标签: mongodb mongodb-php


    【解决方案1】:

    MongoDB 不支持连接。如果要将用户映射到新闻,可以执行以下操作

    1) 在应用层执行此操作。获取用户列表,获取新闻列表并将它们映射到您的应用程序中。如果您经常需要,这种方法非常昂贵。

    2) 如果您需要经常执行上述步骤,则应重新设计架构,以便将新闻文章与用户文档一起存储为嵌入文档。

        {
          "_id": "4ca30373fd0e910ecc000007",
          "login": "user22",
          "pass": "example_pass",
          "date": "2010-09-29"
          "news" : [{  
                       "name": "news 222",
                       "content": "news content 2222",
                       "date": "2010-09-29" 
                    }, 
                    {
                       "name": "news 222",
                       "content": "news content 2222",
                       "date": "2010-09-29"
                    }]
        }
    

    一旦您获得了这种格式的数据,您尝试运行的查询就是隐式的。不过,需要注意的一点是,在这样的模式上分析查询变得很困难。您将需要使用 MapReduce 来获取最近添加的新闻文章和此类查询。

    最后,架构设计和您的应用程序可以处理多少非规范化取决于您希望您的应用程序运行什么样的查询。

    您可能会发现这些链接很有用。 http://www.mongodb.org/display/DOCS/Schema+Design http://www.blip.tv/file/3704083

    希望对您有所帮助。

    【讨论】:

    • 如果您要存储嵌入用户的整篇新闻文章,4MB 对象存储限制是否值得关注?
    • 可以使用dbrefs代替实际文档docs.mongodb.org/manual/applications/database-references
    • 这个答案不再正确,应该更新以反映这一点。
    • @Madbreaks 这个答案在什么方面不正确?我看到的唯一错误是第一句话“MongoDB 不支持连接”,因为 MongoDB 现在有$lookup,它执行左外连接。这个答案确实描述的两个解决方案有什么问题吗?
    • @RoryO'Kane 正如您所注意到的,答案说 MongoDB 不支持连接。这不再严格正确,正如我建议的那样,应该更新答案以澄清这一点。
    【解决方案2】:

    忘记连接。

    查找您的新闻。应用跳过数和限制对结果进行分页。

    $newscollection->find().skip(20).limit(10);
    

    然后循环遍历集合并获取此示例中的 user_id,您将被限制为 10 个项目。现在对用户查询找到的 user_id 项。

    // replace 1,2,3,4 with array of userids you found in the news collection.
    $usercollection.find( { _id : { $in : [1,2,3,4] } } ); 
    

    然后当你打印出新闻时,它可以根据user_id显示来自用户集合的用户信息。

    您对数据库进行了 2 次查询。没有搞乱连接和弄清楚字段名称等。简单!!!

    【讨论】:

      【解决方案3】:

      如果您使用的是新版本的 MongoDB (3.2),那么您会得到与 $lookup 运算符类似的东西。

      使用此运算符的缺点是在运行大型结果集时效率非常低,并且它仅支持匹配的相等性,其中相等性必须在每个集合的单个键之间。另一个限制是右集合应该是与左集合在同一数据库中的非分片集合。

      news 集合上的以下聚合操作使用来自news 集合的字段user_id 和来自@ 的_id 字段将来自news 的文档与来自users 集合的文档连接起来987654329@收藏:

      db.news.aggregate([
          {
              "$lookup": {
                  "from": "users",
                  "localField": "user_id",
                  "foreignField": "_id",
                  "as": "user_docs"
              }
         }
      ])
      

      等效的 PHP 示例实现:

      <?php
      $m = new MongoClient("localhost");
      $c = $m->selectDB("test")->selectCollection("news");
      $ops = array(
          array(
              "$lookup" => array(
                  "from" => "users",
                  "localField" => "user_id",
                  "foreignField" => "_id",
                  "as" => "user_docs"
              )
          )
      );
      $results = $c->aggregate($ops);
      var_dump($results);
      ?>
      

      【讨论】:

      • “$lookup 操作符,可以比作 SQL 中的左外连接” op 专门询问如何进行INNER 连接。
      【解决方案4】:

      您最好将“新闻”嵌入到用户的文档中。

      【讨论】:

      • 最佳答案,nosql 就是让事情顺其自然,让新结构焕发生机
      【解决方案5】:

      你不能在 mongoDB 中做到这一点。从版本 3 开始, Eval() 已被弃用,因此您也不应该使用存储过程。

      我现在知道实现涉及多个集合的服务器端查询的唯一方法是使用 Node.js 或类似的。但是如果你打算尝试这种方法,出于安全原因,我强烈建议你限制允许访问你的机器的 ip 地址。

      此外,如果您的集合不是太大,您可以避免内部连接对它们进行非规范化。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-03-13
        • 1970-01-01
        • 1970-01-01
        • 2020-06-28
        • 2015-01-10
        • 2020-08-31
        • 2020-09-19
        相关资源
        最近更新 更多