Mongoose在聚合中使用子查询来总结数据

我是mongoose新手。 我有这样的模型。

var ForumSchema = new mongoose.Schema({ User_id : {type : Schema.Types.ObjectId, ref : 'User'}, Title : {type : String}, Content : {type : String}, Tags : [{type : String}], isPublic : {type : Boolean, default : false}, Vote : [{ User_id : {type : Schema.Types.ObjectId, ref : 'User'}, Kind : {type : Boolean} }], Rate : [{ User_id : {type : Schema.Types.ObjectId, ref : 'User'}, Count : {type : Number} }], Comment : [{ User_id : {type : Schema.Types.ObjectId, ref : 'User'}, Content : String, Created_at : {type : Date, required : true, default : Date.now} }], Created_at : {type : Date, required : true, default : Date.now}, Updated_at : {type : Date} 

});

我想要得到的论坛数据与Vote总和值是真实的。 像这个json。

 { [ _id : <Some object id>, User_id : <Some object id from User Model>, Title : <Title>, Content : <Content>, Tags : [Some array], isPublic : true, UpVote : 23, .... .... .... ] 

}

在MySQL中,我可以通过使用子查询来做到这一点。 我怎样才能用mongoose做呢?

使用MongoDB服务器3.4及以上版本,你可以运行一个使用$addFields运算符(在Vote数组上有一个$filter的集合pipe道,以过滤那些具有匹配true的Kind属性值的元素,当你得到过滤的数组时,使用它作为$size运算符的inputexpression式,然后计算过滤数组中项目的计数。

考虑以下操作来获得所需的结果:

 Forum.aggregate([ { "$addFields": { "UpVote": { "$size": { "$filter": { "input": "$Vote", "as": "el", "cond": "$$el.Kind" } } } } } ]).exec((err, results) => { if (err) throw err; console.log(results); }) 

说明

在上面,内在的expression

 { "$filter": { "input": "$Vote", "as": "el", "cond": "$$el.Kind" } } 

根据指定的条件select数组的一个子集来返回。 因此,它返回的数组只有那些匹配条件的元素。

input属性是指parsing为数组的expression式。 在上面,input是投票数组。

另一个字段表示input数组中元素的variables名称。 asexpression式通过这个variables访问input数组中的每个元素。

cond字段包含一个expression式,用于确定是否将元素包含在结果数组中。 expression式通过在as指定的variables名来访问元素。

所以在上面,如果被评估数组中的元素的Kind子属性等于true ,用expression式"$$el.Kind" ,那么条件匹配,并且元素被包含在要返回的子集中。

举一个简单的例子,举个例子,这个高级expression式:

 { "$filter": { "input": [ { "Kind": true, "User_id": "58afed97bc343887a9ac9206" }, { "Kind": false, "User_id": "58ad50a429b2961777f91c97" }, { "Kind": true, "User_id": "58b3f0f598501abacd8ff391" } ], "as": "el", "cond": { "$eq": ["$$el.Kind", true] } } } 

返回数组

 [ { "Kind": true, "User_id": "58afed97bc343887a9ac9206" }, { "Kind": true, "User_id": "58b3f0f598501abacd8ff391" } ] 

有条件的部分

 "cond": { "$eq": ["$$el.Kind", true] } 

可以简化为

 "cond": "$$el.Kind" 

因为"$$el.Kind"expression式已经评估为布尔值。

例如, $size运算符可以计算数组中元素的数量,例如expression式

 { "$size": { "$filter": { "input": [ { "Kind": true, "User_id": "58afed97bc343887a9ac9206" }, { "Kind": false, "User_id": "58ad50a429b2961777f91c97" }, { "Kind": true, "User_id": "58b3f0f598501abacd8ff391" } ], "as": "el", "cond": { "$eq": ["$$el.Kind", true] } } } } 

被表示为

 { "$size": [ { "Kind": true, "User_id": "58afed97bc343887a9ac9206" }, { "Kind": true, "User_id": "58b3f0f598501abacd8ff391" } ] } 

并返回结果2作为计数。

相反,DownVote计数,相同的逻辑适用:

 Forum.aggregate([ { "$addFields": { "UpVote": { "$size": { "$filter": { "input": "$Vote", "as": "el", "cond": "$$el.Kind" } } }, "DownVote": { "$size": { "$filter": { "input": "$Vote", "as": "el", "cond": { "$not": ["$$el.Kind"] } } } } } } ]).exec((err, results) => { if (err) throw err; console.log(results); }) 

对于早期的MongoDB版本3.2,您将需要投影文档中的每个其他元素:

 Forum.aggregate([ { "$project": { "User_id" : 1, "Title" : 1, "Content" : 1, "Tags" : 1, "isPublic" : 1, "UpVote" : { "$size": { "$filter": { "input": "$Vote", "as": "el", "cond": "$$el.Kind" } } }, .... .... .... } } ]).exec((err, results) => { if (err) throw err; console.log(results); }) 

对于不支持$filter操作符的版本,请使用$setDifference操作符:

 Forum.aggregate([ { "$project": { "User_id" : 1, "Title" : 1, "Content" : 1, "Tags" : 1, "isPublic" : 1, "UpVote" : { "$size": { "$setDifference": [ { "$map": { "input": "$Vote", "as": "el", "in": { "$cond": ["$$el.Kind", "$$el", false] } }}, [false] ] } }, .... .... .... } } ]).exec((err, results) => { if (err) throw err; console.log(results); }) 

你可以在MongoDB中使用聚合

 db.getCollection('forum').aggregate([{ $unwind: "$Vote" }, { $match: { "Vote. Kind": true } }, { $group: { _id: '$_id', "User_id": { '$first': '$User_id' }, "Title": { '$first': '$Title' }, UpVote: { $sum: 1 } } } ]) 

你也可以在mongoose中使用这个相同的查询,最后得到最多的票数