2014-09-21 78 views
1

我有這樣的模式:貓鼬選擇subdoc的領域

mongoose.model "Ticket", { 
    title: String 
    body: String 
    likes: Number 
    comments: [{ 
    body: String 
    upvotes: Number 
    downvotes: Number 
    }] 
} 

我的代碼查詢

q = @model.findOne {"comments._id": oid}, {"comments.$": 1} 

q.select "comments.upvotes" 
q.exec (err, result) => 
    console.log(result.comment[0].downvotes) # 6 

正如你看到的,選擇不適合的工作SUBDOCS,它也沒有返回選定字段。如何解決這個問題?

回答

2

這是MongoDB如何處理數組元素的基本投影。雖然你可以做這樣的事情:

Model.findOne({}, { "comments.upvotes": 1 },function(err,doc) { 

}) 

而這也只是從註釋陣列匹配條件的所有文件,當然,所有的數組元素的子文檔內歸還「upvotes」字段,你不能使用positional $運算符將其與選定的位置投影相結合。這基本上源於「理論」一般你實際上想要返回整個數組。所以這就是它一直工作的方式,不可能很快改變。

爲了獲得您想要的,您需要aggregation framework提供的文檔操作的擴展功能。這使您如何返回文檔的更多控制:MongoDB的自2.6

Model.aggregate(
    [ 
     // Match the document containing the array element 
     { "$match": { "comments._id" : oid } }, 

     // Unwind to "de-normalize" the array content 
     { "$unwind": "$comments" }, 

     // Match the specific array element 
     { "$match": { "comments._id" : oid } }, 

     // Group back and just return the "upvotes" field 
     { "$group": { 
      "_id": "$_id", 
      "comments": { "$push": { "upvotes": "$comments.upvotes" } } 
     }} 
    ], 
    function(err,docs) { 


    } 
); 

用現代的版本中,你甚至可以這樣做:

Model.aggregate(
    [ 
     { "$match": { "comments._id" : oid } }, 
     { "$project": { 
      "comments": { 
       "$setDifference": [ 
        { "$map": { 
         "input": "$comments", 
         "as": "el", 
         "in": { 
          "$cond": [ 
           { "$eq": [ "$$el._id", oid ] }, 
           { "upvotes": "$$el.upvotes" }, 
           false 
          ] 
         } 
        }}, 
        [false] 
       ] 
      }} 
     }} 
    ], 
    function(err,docs) { 

    } 
) 

和使用該$map$setDifference運營商做在沒有首先處理階段的情況下對陣列內容進行「在線」過濾。

因此,如果您想要更多地控制文檔返回的方式,那麼在使用嵌入式文檔時,彙總框架就是實現它的方法。

+0

看起來很有意思。謝謝 – Vinz243 2014-09-22 19:02:51