2014-07-08 43 views
0

這是查找user1收到的所有文檔的正確查詢,其中user1的archived = true?更正Mongoose語法以查詢user1存檔的消息?

var query = { 
     "to.username": user1, 
     "to.section.archive": true 
}; 

Models.Message.find(query).sort([['to.updated','descending']]).exec(function (err, messages) { 

嵌入「到」一個消息架構的陣列的樣品看起來像這樣:

"to" : [ 
    { 
     "user" : ObjectId("53b96c735f4a3902008aa019"), 
     "username" : "user1", 
     "updated" : ISODate("2014-07-08T06:23:43.000Z"), 
     "_id" : ObjectId("53bb8e6f1e2e72fd04009dad"), 
     "section" : { 
      "in" : true, 
      "out" : false, 
      "archive" : true 
     } 
    } 
] 

查詢應只返回上述(user1和歸檔爲true)..不是這個下一個doc該文檔(檔案是真實的,而不是用戶1):

"to" : [ 
    { 
     "user" : ObjectId("53b96c735f4a3902008aa019"), 
     "username" : "user2", 
     "updated" : ISODate("2014-07-08T06:24:42.000Z"), 
     "_id" : ObjectId("53bb8e6f1e2e72fd04009dad"), 
     "section" : { 
      "in" : true, 
      "out" : false, 
      "archive" : true 
     } 
    } 
] 

回答

1

您希望$elemMatch運營商選擇具有條件和01元操作投影:

Models.Message.find(
    { 
     "to": { 
      "$elemMatch": { 
       "username": "user2", 
       "section.archive": true 
      } 
     } 
    }, 
    { "created": 1, "message": 1, "to.$": 1 } 
).sort([['to.updated','descending']]).exec(function (err, messages) { 

}); 

請注意,這僅投影「第一」元件匹配的作品。此外,您還希望對匹配的數組元素的值進行「排序」,並且您無法通過.find().sort()修改器來完成此操作。

如果你想在數組中有多個匹配,那麼你需要使用聚合方法。這確實更爲複雜的「過濾」和「投影」比是可能的,否則:

Models.Message.aggregate([ 

    // Match documents 
    { "$match": { 
     "to": { 
      "$elemMatch": { 
       "username": "user2", 
       "section.archive": true 
      } 
     } 
    }}, 

    // Unwind to de-normalize 
    { "$unwind": "$to" }, 

    // Match the array elements  
    { "$match": { 
     "to.username": "user2", 
     "to.section.archive": true 
    }}, 

    // Group back to the original document 
    { "$group": { 
     "_id": "$_id", 
     "created": { "$first": "$created" }, 
     "message": { "$first": "$message" }, 
     "to": { "$push": "$to" } 
    }} 

    // Sort the results "correctly" 
    { "$sort": { "to.updated": -1 } } 

],function(err,messages) { 

}); 

或者,可以避免使用$unwind$group通過與MongoDB中2.6或更高的操作者$map應用一些邏輯。只是看,作爲$setDifference應用到所產生的「過濾」數組你的數組內容是「真正的」獨特性:

Models.Message.aggregate([ 
    { "$match": { 
     "to": { 
      "$elemMatch": { 
       "username": "user2", 
       "section.archive": true 
      } 
     } 
    }}, 
    { "$project": { 
     "created": 1, 
     "message": 1, 
     "_id": 1, 
     "to": { 
      "$setDifference": [ 
       { 
        "$map": { 
         "input": "$to", 
         "as": "el", 
         "in": { 
          "$cond": [ 
           { 
            "$and": [ 
             { "$eq": [ "$$el.username", "user2" ] }, 
             "$$el.section.archive" 
            ] 
           }, 
           "$$el", 
           false 
          ] 
         } 
        } 
       }, 
       [false] 
      ] 
     } 
    }}, 
    { "$sort": { "to.updated": -1 } } 

],function(err,messages) { 

}); 

甚至使用$redact

Models.Messages.aggregate([ 
    { "$match": { 
     "to": { 
      "$elemMatch": { 
       "username": "user2", 
       "section.archive": true 
      } 
     } 
    }}, 
    { "$redact": { 
     "$cond": { 
      "if": { 
       "$and": [ 
        { "$eq": [ 
         { "$ifNull": [ "$username", "user2" ] }, 
         "user2" 
        ] }, 
        { "$ifNull": [ "$section.archive", true ] } 
       ] 
      }, 
      "then": "$$DESCEND", 
      "else": "$$PRUNE" 
     } 
    }}, 
    { "$sort": { "to.updated": -1 } } 
],function(err,messages) { 

}); 

但要小心爲$redact工作在所有文檔的級別,所以你的結果可能是意想不到的。

可能你的「to」數組實際上只有單個條目可以匹配,所以通常標準投影應該沒問題。但這裏是你如何在MongoDB的數組元素中進行「多重」匹配。

+0

這真的很棒..很多很多謝謝 – StackThis

+0

你會推薦什麼方法來返回每個匹配文檔的全部內容?經過測試,我使用$ unwind + $ group聚合,其中所有其他字段都是$首先累積的。如何在最佳實踐中排名? – StackThis

+0

@StackThis剛剛注意到,當然你想對那些匹配元素的「更新」日期進行「排序」。所以當然你需要一個聚合方法來做到這一點。你在做什麼很好,其他方法是新的介紹。如果您正在查找多個數組匹配項,您可能還需要在分組中輸入「$ min」或「$ max」日期值進行排序。甚至可能在分組之前對這些匹配進行排序。 –