我将通过以下方案真实地为您提供帮助。 我有这个架构:
var Song = Schema({
author: { type: Schema.Types.ObjectId, ref: 'user' },
title: String,
photo: String,
date: Date,
duration: Number,
views: [{ type: Schema.Types.ObjectId, ref: 'user' }],
likes: [{ type: Schema.Types.ObjectId, ref: 'user' }]
})
var User = mongoose.Schema({
email:String,
name:String,
gender: String,
birthday: String,
city: String,
continent: String
});
我想写一个查询,向每个大陆的用户提供他的歌曲组中的总喜欢和观看次数。例如:
{continent: 'Asia', views:4000, likes:5000},
{continent: 'Europe', views:3200, likes:4500}
此外,我很高兴知道它是否被认为是一个重要的查询",也许我认为保存类似的东西并将视图视为userId与大陆的组合是一个更聪明的想法。
答案 0 :(得分:1)
而不是.populate()
(这是“客户端”操作),您希望数据在服务器上“加入”,其中.aggregate()
是“服务器”端操作。这是$lookup
运算符的用途:
在$map
$concatArrays
“类型”和$lookup
可能是最优的。
Song.aggregate([
{ "$project": {
"author": "$author",
"data": {
"$concatArrays": [
{ "$map": {
"input": "$views",
"as": "el",
"in": { "type": "views", "_id": "$$el" }
}},
{ "$map": {
"input": "$likes",
"as": "el",
"in": { "type": "likes", "_id": "$$el" }
}}
]
}
}},
{ "$unwind": "$data" },
{ "$lookup": {
"from": "users",
"localField": "data._id",
"foreignField": "_id",
"as": "data._id"
}},
{ "$unwind": "$data._id" },
{ "$group": {
"_id": {
"author": "$author",
"continent": "$data._id.continent"
},
"views": {
"$sum": { "$cond": [ { "$eq": [ "$data.type", "views" ] }, 1, 0 ] }
},
"likes": {
"$sum": { "$cond": [ { "$eq": [ "$data.type", "likes" ] }, 1, 0 ] }
}
}}
], function(err, results) {
})
你在一开始就做“阵列加入”,因为在某些时候你想要在单个数组中使用“喜欢”和“视图”,因为如果我们尝试用稍后的$unwind
操作单独处理它们(和你需要为了“计算”“大陆”的价值,然后你得到一个“笛卡尔积”,因为一个数组的内容将乘以另一个数组中的内容。
因此,我们用“类型”标记“加入”,因为它们不再位于不同的字段中,我们仍然需要区分“喜欢”和“视图”以进行计数。
$lookup
操作能够在最现代的版本中使用“平面”数组,但不能使用从第一阶段构建的“文档数组”。只需$unwind
即可先处理。
完成$lookup
后,此表单中的结果将是"data._id"
路径中包含的每个结果的单个元素数组。为了继续处理我们$unwind
。
最后你$group
,其中“复合键”用于从连接数据获得的“作者”和“大陆”值。为了计数,每个“喜欢”和“视图”都应用于$cond
表达式,这是一个三元(if / then / else)运算符。给定第一个参数中的条件,其中该条件为true
,则返回第二个参数值,或者当false
为第三个参数时。
这些表达式的结果传递给$sum
以累积,因此当条件匹配时,返回正数并累积分组键。
所有聚合都是“重型”操作,执行“连接”实际上被认为更加“沉重”。
在很多情况下,您的应用程序在运行时执行此类查询没有任何问题。如果这对您的数据以有效的速度运行,那真的可以归结为。如果数据足够大以至于此类操作需要花费过多时间,那么您应该通过在单独的记录中累积此类摘要数据来“预聚合”。在这种情况下,增加每个作者每个大陆的“喜欢”或“查看”计数等。