2014-06-17 10 views
0

我有以下結構的架構排除性能:貓鼬(MongoDB的):在Dictionary像模式類型

var schema = mongoose.Schema({ 
    answers: {type: mongoose.Schema.Types.Mixed} 
}); 

我使用的答案字段作爲一個對象(關聯數組實現像詞典) 。下面是一個示例:

{ 
    "__v": 0, 
    "_id": { 
     "$oid": "53a0251c50d0536c1bfc6006" 
    }, 
    "answers": { 
     "fea": { 
      "viewed": false 
     }, 
     "3d2": { 
      "viewed": true, 
      "value": true 
     }, 
     "4fr": { 
      "viewed": true, 
      "value": true 
     }, 
     "84h": { 
      "viewed": false 
     }, 
     ... 
    } 
} 

在查詢中,我只想選擇每個條目的「值」字段。通過選擇語法怎麼可能?這當然不起作用:

XY.find(...) 
.select({'answers': true, 'answers.*.value': false}) 
.exec(...); 

也許我必須以另一種方式設計數據?

最好的問候, 克斯滕

回答

0

你不應該有「明確的價值」模型作爲「鑰匙」的名字。這是非常糟糕的做法。考慮你會在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) { 

    } 
) 

但實際上,考慮改變你的結構,因爲它使事情進行查詢等操作更加靈活。

+0

嗨尼爾,謝謝你的回覆。對不起,這很長的延遲。以我的方式建模數據的巨大好處是,它會在客戶端(瀏覽器)產生一個字典(對象)。你的模型是一個數組,搜索速度很慢。或者我錯了? – loxy