2016-02-18 41 views
0

我有2個相關的集合。甲板和事實。學習MongoDB如何使用2個集合中的數據

甲板看起來是這樣的:

{ 
    _id: ObjectId("123456789123456789"), 
    title: "test deck" 
    isActive: true 
} 

一個事實是這樣的

{ 
    _id: ObjectId("111111324324434"), 
    deckId: ObjectId("123456789123456789") 
    title: "test fact" 
} 

我來自一個SQL背景,所以我想SELECT * FROM facts LEFT JOIN decks ON decks._id = facts.deckId WHERE deck.isActive = true

的唯一途徑,我可以想出解決通過一個微型腳本。

var deckIds = db.decks.find({isActive: false}, {_id: true}).toArray().map(function(item) { 
return item._id; 
}); 
db.facts.find({deckId: {$in: deckIds}}); 

這是最好的方法嗎?在Mongo中有更高性能的方法嗎?我看着map-reduce,但我無法弄清楚如何在那裏做這件事,它看起來像更多的代碼。我最終想要做的是刪除deck.isActive = false的事實。

+4

的[我如何執行SQL加入MongoDB中等價?(http://stackoverflow.com/questions/2350495/how-do-i-perform-the-sql-join-equivalent-in-可能的複製mongodb) – joao

+0

我的問題是「這是最好的方式」。我沒有mongo 3.2,所以我不能使用$ lookup。所以上面的微腳本是最好的? –

+1

如果您沒有使用mongo 3.2,則沒有多少選項。您可以設計數據模式,以便不需要執行連接,也可以在客戶端執行連接(如發佈的腳本)。 – joao

回答

1

MongoDB是一個NoSQL數據庫,所以你不會得到原生的JOIN功能。你應該手動進行,就像你正在做的那樣。

但是,需要考慮的一個重要問題是數據建模。與關係數據庫中的最佳實踐相反,NoSQL模型往往是非規範化的,這就是儘可能標準化的關係數據庫。

所以,也許,你的其實文件可能包括其他甲板的字段,查詢簡化的緣故。我並不是說這對你來說是最好的選擇,但只是警告你,在非關係數據庫中,當涉及到數據建模時,你應該會有所不同。當然,您選擇的每種模型都會影響寫作和閱讀,這在很大程度上取決於您的工作量。這需要一些鍛鍊和練習,但是您可以遵循一些準則。看看official documentation

有來自年底Packt出版過這個話題一本好書,叫MongoDB的數據建模

好的是,MongoDB在功能方面非常強大(可以嵌套文檔,數組,就地操作等),所以您有很多選擇來實現您所需的功能。

此外,不要忘記根據您的查詢和更新創建indexes_id字段自動索引,其餘不是)。

+0

是的,我同意,我經常需要分別對事實和套牌進行審查,因此將它們分開是有意義的。我只是不確定是否可以使用map-reduce或聚合函數。 –

+0

Map只有當你有碎片時,Reduce纔有意義,當你想要在後臺運行的某些聚合通過不同的服務器傳播時。其結果將被放入另一個收藏。它似乎並不是你所需要的。說實話,我對Mongo的Aggregation框架並不是很熟悉,但據我所知,它也只適用於單一集合,所以你可以回到同樣的問題:集合之間的關係。 –

1

雖然這是「SQL」思維方式,但Mongo確實支持這種工作,在Mongo 3.2中添加了$ lookup(https://docs.mongodb.org/manual/reference/operator/aggregation/lookup/)。我建立了你的數據,但使用小寫名字;以下工作產生了一個快速連接。

db.facts.aggregate([{$lookup: {from: "decks", localField: "deckId", foreignField: "_id", as: "deck_data"}}]);

產生

{ "_id" : ObjectId("56c5eb065b2de3fa9f8a9d0c"), "title" : "test fact", "deckId" : ObjectId("56c5eadb5b2de3fa9f8a9d0b"), "deck_data" : [ { "_id" : ObjectId("56c5eadb5b2de3fa9f8a9d0b"), "title" : "test deck", "isActive" : true } ] }

您只需通過添加自己的對象數組應用其他聚合步驟。我建議$匹配(相當於Find())和$ project(允許選擇字段)。

+0

如果目標是根據甲板上的字段刪除事實,那麼您將如何使用聚合來執行刪除操作?你會用這個獲得一個ID數組,然後用$ in做第二次刪除嗎? –

+0

我還沒有試過這個,但是看起來你可以通過$ match和$ project階段製作你想要的集合,然後使用$ out將它重新寫回到同一個集合中。請參考:https://docs.mongodb.org/manual/reference/operator/aggregation/out/ –