关于计算值聚合框架的mongodb排序/查询?

时间:2015-08-25 17:27:47

标签: ruby mongodb mapreduce mongodb-query aggregation-framework

我有一个与其他集合有关系的集合,我想为用户选择最相关的记录选择,如下所示:

拥有this.some_collection_id ==' someid' &安培;&安培; this.another_collection_id ==' another_id' 然后记录有this.some_collection_id ==' someid' 然后记录有this.another_collection_id ==' another_id' 其他记录

示例:让我们说主要收藏是故事,每个故事都有一个' interest_group'和一个位置'。所有用户都有一个主要兴趣小组'和一个位置'。我想查询特定用户的前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条记录左右)

有没有办法以不同的方式做到这一点?我也检查了聚合框架,但我没看到这将如何解决这个特定的查询。

1 个答案:

答案 0 :(得分:2)

这里提到的问题并没有真正解释这里的逻辑以及它应该如何,但是如果我确实抓住了你的一般意义那么这应该是上面的模拟,你想要的额外增强: / p>

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除了_idscore之外什么都不做,所以我在这里也是这样做的。但您可以根据需要添加其他字段。除非另有说明,否则_id当然是隐式的,例如"_id" => 0

剩下的就是“得分”值上的$sort和排序后总结果的$limit。哪些都是mapReduce无法做到的事情。

这基本上是根据匹配的属性添加权重,然后将结果“排序”和“限制”到最高分。另请注意,作为“数据结构”,您要使用的聚合管道中的变量只是本机代码,并且不需要使用mapReduce执行“stringify”处理。