我確實對Moped查詢表格有一個普遍的偏好,因爲它可以在較低級別上工作,並且可以利用MongoDB查詢操作符的完整功能集。對某些人來說,這可能看起來不是很「高尚」,但有一些優勢。特別是當解決方案涉及所以爲了找到匹配的先決條件的學生已經採取,你會建立這樣的語句課程,該課程採用.aggregate()
:
Course.collection.aggregate([
// Filters the documents, not an exact match but a start
{ "$match" => {
"prerequisites" => { "$in" => [ "a", "b" ] },
}},
// Unwind the array
{ "$unwind" => "$prerequisites" },
// Tag only the matching entries
{ "$project" => {
"prerequisites" => 1,
"matching" => { "$or" => [
{ "$eq" => [ "$prerequisites", "a" ] },
{ "$eq" => [ "$prerequisites", "b" ] },
]}
}},
// Group back to the course _id
{ "$group" => {
"_id" => "$_id",
"prerequisites" => { "$push" => "$prerequisites" },
"matching" => { "$min" => "$matching" }
}},
// Match only the true values (all prerequisites met)
{ "$match" => { "matching" => true } },
// Project only the wanted fields
{ "$project" => { "prerequisites" => 1 } }
])
所以「courses_taken」的每個元素都被添加到$in
運算符中,因此只有包含某些內容的課程纔會匹配。但是,這當然不能完全過濾學生必須滿足所有先決條件課程的條件,這裏的要點是將文檔數量減少到可能匹配的數量。
數組解開後,每個值都可以進行比較。這就是$project
通過從數組元素構建語句來測試是否找到該值。所以在$or
條件下,任何不匹配的東西都會返回false
作爲該值。
在後面的$group
階段,由於文檔被重新放回原來的形式,該「匹配」測試的值將被存儲在文檔中。這意味着,如果prerequisites數組中的任何元素被視爲匹配,則整個文檔的值將被視爲false
。
下一個$match
用於過濾任何課程,因此會包含課程先決條件,而該課程先決條件與用於輸入的學生所採用的課程不匹配。所以現在只留下可以採取的課程,最後$project
只是刪除「匹配」字段(通過省略),以便文檔現在處於原始形式。
如果你確實有MongoDB版本2。6(剛剛發佈了寫作的)或向上,則是聚集新的運營商,使更簡單的聲明:
Course.collection.aggregate([
{ "$match" => {
"prerequisites" => { "$in" => [ "a", "b" ] }
}},
{ "$project" => {
"prerequisites" => 1,
"diff" => { "$size" => {"$setDifference" => [
"$prerequisites",
[ "a", "b" ]
]}}
}},
{ "$match" => { "diff" => 0 } },
{ "$project" => { "prerequisites" => 1 } }
])
因此,這使得使用新的運營商對於$setDifference
它可以直接比較陣列發現不在集合中的元素,以及使用$size
將返回測試數組的長度。由於任何包含不在課程中的學員要素的課程將返回這些元素作爲* $setDifference
的結果,那麼可以從整體結果中排除除0
之外的「大小」的任何結果。
除了簡單得多,有一些速度優勢外,還可以通過將學生的課程數組直接傳遞到管道查詢的構建中來避免生成的複雜性,而且不必亂用構建第一個例子中使用的「相等」測試語句。
但是,這給了你相當強大的方式來做這種匹配,而不訴諸循環結果的代碼。它還指出,聚合框架的使用不僅僅是對結果進行分組,而是一個非常強大的查詢工具。
這實際上並未顯示您的數據或模型的佈局。沒有人知道如何構建您的查詢。請在你的問題中包含這些細節。 –
好的,我已添加更多詳細信息 –