Mongoose 选择子文档字段

Posted

技术标签:

【中文标题】Mongoose 选择子文档字段【英文标题】:Mongoose select subdoc fields 【发布时间】:2014-11-15 15:01:17 【问题描述】:

我有这样的架构:

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

如您所见,选择不适用于子文档,它还会返回未选择的字段。如何解决?

【问题讨论】:

【参考方案1】:

这就是 MongoDB 使用数组元素处理基本投影的方式。虽然你可以这样做:

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

)

这只会从 cmets 数组的子文档中返回“upvotes”字段,用于匹配条件的所有文档和所有数组元素,当然,您不能将其与使用 positional $ 的选定位置投影结合起来操作员。这基本上源于 "theory" 您实际上想要返回整个数组的一般。所以这就是它一直以来的工作方式,而且不太可能很快改变。

为了得到您想要的,您需要aggregation framework 提供的文档操作扩展功能。这使您可以更好地控制文档的返回方式:

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) 


    
);

或者在 MongoDB 2.6 之后的现代版本中,您甚至可以这样做:

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 阶段。

因此,如果您想更好地控制文档的返回方式,那么在处理嵌入式文档时,聚合框架就是实现此目的的方法。

【讨论】:

看起来很有趣。谢谢 新版本的 MongoDB 现在有更好的方法吗?

以上是关于Mongoose 选择子文档字段的主要内容,如果未能解决你的问题,请参考以下文章

使用 Mongoose 查找子文档字段部分匹配给定条件的文档

使用 Mongoose 查找子文档字段部分匹配给定条件的文档

Mongoose如何更新子文档字段?

具有必填子文档字段的 Mongoose 架构

Mongoose:如何将附加字段添加到子文档数组中

Mongoose:如何将附加字段添加到子文档数组中