8

我正在使用 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
4

5 回答 5

19

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

我希望这会有所帮助。

于 2010-10-01T01:38:47.130 回答
14

忘记连接。

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

$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 次查询。没有搞乱连接和弄清楚字段名称等。简单!!!

于 2012-07-16T19:40:52.717 回答
5

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

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

集合上的以下聚合操作使用集合中的字段和集合中的字段将来自集合的文档与来自集合news的文档连接起来:newsusersuser_idnews_idusers

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);
?>
于 2016-01-14T15:00:27.640 回答
4

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

于 2010-09-30T14:33:05.010 回答
0

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

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

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

于 2015-09-04T14:21:06.810 回答