你不應該有「明確的價值」模型作爲「鑰匙」的名字。這是非常糟糕的做法。考慮你會在SQL數據庫中做什麼。你會爲你想要的東西的不同「名稱」創建「字段/列」嗎?
不,你不會。你有一個通用的字段,指定一個「類型」,然後你有其他人保存數據。沒有什麼變化此處
{
"_id": {
"$oid": "53a0251c50d0536c1bfc6006"
},
"answers": [
{ "type": "fea", "viewed": false },
{ "type": "3d2", "viewed": true, "value": true },
{ "type": "4fr", "viewed": true, "value": true },
{ "type": "84h", "viewed": false },
...
]
}
現在,這是很容易使用類似的聚合框架,使內容的投影像你想:
隨着現代MongoDB的2.6及以後,你可以使用$map
和$setDifference
到陣列篩選,而無需使用$unwind
:
Model.aggregate(
[
{ "$project": {
"answers": {
"$setDifference": [
{
"$map": {
"input": "$answers",
"as": "el",
"in": {
"$cond": [
1,
{
"type": "$$el.type",
"value": { "$ifNull": [ "$$el.value", false ] }
},
false
]
}
}
},
[false]
]
}
}}
],
function(err,result) {
}
);
或者與舊版本的預2.6:
Model.aggregate(
[
{ "$unwind": "$answers" },
{ "$group": {
"_id": "$_id",
"answers": {
"$push": {
"type": "$answers.type",
"value": { "$ifNull": [ "$answers.value", false ] }
}
}
}}
],
function(err,result) {
}
);
當然,你可以通過添加一個邏輯評價作爲第一個參數的操作者$cond
在$map
執行「過濾器」的陣列的結果某些條件。或者在$unwind
和$group
階段之間使用$match
流水線階段。
無論哪種形式,您都可以毫無問題地對結果進行重新塑造,並且是處理此問題的最快方式,這與使用數組而非嵌入對象的鍵實際上是「數據」項的強大優勢相關。
如果你遇到這個問題,那麼你需要使用JavaScript評估來處理mapReduce。這個運行的比聚合框架慢得多,因爲需要調用並運行JavaScript解釋過程:
Model.mapReduce(
{
"map": function() {
for (var k in this.answers) {
this.answers[k] = this.answers[k].hasOwnProperty("value")
? this.answers[k].value : false;
}
var id = this._id;
delete this._id;
emit(id, this);
},
"reduce": function(){}
},
function(err,docs) {
}
)
但實際上,考慮改變你的結構,因爲它使事情進行查詢等操作更加靈活。
嗨尼爾,謝謝你的回覆。對不起,這很長的延遲。以我的方式建模數據的巨大好處是,它會在客戶端(瀏覽器)產生一個字典(對象)。你的模型是一個數組,搜索速度很慢。或者我錯了? – loxy