我有一个与其他集合有关系的集合,我想为用户选择最相关的记录选择,如下所示:
第一条记录包含 this.some_collection_id == 'someid' && this.another_collection_id == 'another_id' 然后记录有 this.some_collection_id == 'someid' 然后记录具有 this.another_collection_id == 'another_id' 然后是其他记录
示例:假设主要集合是故事,每个故事都有一个“interest_group”和一个“location”。所有用户都有一个“主要兴趣组”和一个“位置”。我想查询特定用户的前 100 个最有趣的故事,具有相同兴趣组和位置的故事应权重 5,相同兴趣组仅 3,相同位置仅 2,其余 1。
我想在查询期间奖励这些积分,以便我可以根据这些积分对故事集合进行排序并返回前 100 个。
因此,我可以执行 4 个单独的查询并合并客户端结果(不太漂亮),或者我可以尝试以正确的顺序获取集合。
到目前为止,我已经提出了以下内容:
map = %Q{
function() {
var score = 1;
if (this.some_id == "#{some_id}") {
score = score + 3
}
if (this.another_id == "#{another_id}") {
score = score + 2
}
emit(this._id, { _id: this._id, score: score });
}
}
reduce = %Q{
function(key, values) {
return values;
}
}
MyCollection.map_reduce(map, reduce).out(inline: true)
这将正确返回带有分数的整个记录集合,但是我无法对分数进行排序,因此我必须在客户端进行排序(也很丑陋,因为我只需要前 100 条记录左右)
有没有办法以不同的方式做到这一点?我还检查了聚合框架,但我不知道这将如何解决这个特定的查询。
最佳答案
这里提到的问题并没有真正解释这里的逻辑,但如果我确实理解了你的一般含义,那么这应该与上面的内容非常相似,并且还具有你想要的额外增强功能:
MyCollection.collection.aggregate([
{ "$project" => {
"score" => {
"$add" => [
{ "$cond" => [
{ "$or" => [
{ "$eq" => [ "$some_id" => some_id_var1 ] },
{ "$eq" => [ "$some_id" => some_id_var2 ] },
{ "$eq" => [ "$some_id" => some_id_var3 ] },
{ "$eq" => [ "$some_id" => some_id_var4 ] }
]},
3,
0
]},
{ "$cond" => [
{ "$or" => [
{ "$eq" => [ "$another_id" => another_id_var1 ] },
{ "$eq" => [ "$another_id" => another_id_var2 ] },
{ "$eq" => [ "$another_id" => another_id_var3 ] },
{ "$eq" => [ "$another_id" => another_id_var4 ] }
]},
2,
0
]},
1
]
}
}},
{ "$sort" => { "score" => -1 } },
{ "$limit" => 100 }
])
本质上,这与“some_id”和“another_id”字段与某些变量输入进行比较以查看它们是否匹配并返回分数是完全相同的。我在这里所做的补充是您提到“4 个查询”,因此听起来像是变量更改。这应该与 $or
相适应。在这两种情况下都改为条件。如果您确实只比较每种情况下的一个值,则只需删除包装 $or
。
$cond
运算符本身是“if/then/else”三元运算。因此,第一个参数是“if”,接下来的参数分别是 true/false
返回的值。在这种情况下,您的归因分数或 0
。
然后用 add
来结束这一切生成每个文档的“总分”,其逻辑与您正在使用的逻辑相同。
另请注意 $project
要求您“明确”输出结果中所需的所有字段。你的mapReduce除了_id
和score
什么都不做,所以我在这里也做同样的事情。但您可以根据需要添加其他字段。 _id
当然总是隐式的,除非另有指定,例如 "_id"=> 0
。
剩下的就是 $sort
关于“分数”值,以及 $limit
为排序后的总结果。这都是mapReduce 无法做到的。
这基本上是根据匹配的属性添加权重,然后“排序”并将结果“限制”为最高分。另请注意,作为“数据结构”,您要使用的聚合管道中的变量只是 native 代码,不需要您使用 mapReduce 进行的“字符串化”处理。
关于ruby - mongodb 对计算值聚合框架进行排序/查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32210397/