2010-09-30 39 views
8

我正在使用Mongo PHP擴展。mongodb php - 如何做「INNER JOIN」式查詢

我的數據是這樣的:

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

在用戶的文檔中嵌入「新聞」可能會更好。

+0

最佳答案,nosql全部是關於lettin g新的結構將會煥發新生 – 2015-02-05 04:28:14

18

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

我希望這有幫助。

+0

如果您要存儲與您的用戶一起嵌入的全部新聞文章,4MB對象存儲是否會受到限制? – jocull 2011-03-17 18:07:58

+0

您可以使用dbrefs而不是實際的文檔http://docs.mongodb.org/manual/applications/database-references/ – Optimus 2012-08-12 10:16:35

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個查詢。沒有搞亂連接和搞清楚字段名稱等簡單!

0

你不能在mongoDB中做到這一點。從版本3 Eval()已棄用,因此您不應該使用存儲過程。

我知道實現涉及多個集合的服務器端查詢的唯一方法是使用Node.js或類似的方法。但是,如果您要嘗試這種方法,出於安全原因,我強烈建議您限制允許訪問您的計算機的IP地址。另外,如果你的集合不是太大,你可以避免內部連接對它們進行非規範化。

4

如果您使用的是新版本的MongoDB(3.2),那麼您會得到與運算符類似的東西,它可以比喻爲SQL中的左外連接。

使用此運算符的缺點是,運行在大型結果集上時效率非常低,並且它只支持在每個集合中的單個鍵之間必須存在等於的相等匹配。另一個限制是,右收集應該是與左收集相同數據庫中的未加固定集合。

news收集以下聚合操作加入該文件從news使用領域user_idnews收集從users收集的文件,並從users收集_id領域:

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); 
?>