mongooseselectsubdoc领域

我有这样的模式:

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 

正如你所看到的,select不能用于subdocs,它也不会返回选定的字段。 如何解决这个问题?

这是MongoDB如何处理数组元素的基本投影。 虽然你可以做这样的事情:

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

这只会从comments数组的子文档中返回匹配条件和所有数组元素的所有文档中的“upvotes”字段,您不能使用位置$运算符将其与选定的位置投影相结合。 这基本上来自“理论”一般来说你实际上想要返回整个数组。 所以这就是它一直工作的方式,不可能很快改变。

为了得到你想要的东西,你需要扩展框架提供的文档操作能力。 这使您可以更好地控制文档的返回方式:

 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) { } ); 

或者从2.6开始,在MongoDB的现代版本中,甚至可以这样做:

 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运算符来对数组内容进行“在线”过滤,而无需先处理$unwind阶段。

所以如果你想更多地控制文档的返回方式,那么在使用embedded式文档时,汇总框架就是这样做的。