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名称。 as
expression式通过这个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中使用这个相同的查询,最后得到最多的票数