MongoDB按相关性排序(混合$和$或)

时间:2017-05-23 19:38:19

标签: mongodb sorting mongodb-query aggregation-framework

有两个文件,如:

{
    "name": "hello",
    "family": 1
},
{
    "name": "world",
    "family": 1,
    "category": 2
}

和类似的查询:

doc.find({$or: [{family: 1}, {category: 2}]})

如何将结果与匹配2个条件(" world")作为第一个结果排序,但仍然只有1个条件作为最后结果匹配(" hello&# 34;)?

我不能使用默认的$和运算符,因为我不会看到"你好"文件不符合这两个条件。

我看到聚合如何有所帮助,但是对于一个更复杂的例子而不是大量的计算,我猜这是常见的用例,必须有一些明显的我缺失

1 个答案:

答案 0 :(得分:1)

您不能使用简单的.find()语句执行此类查询(双关语)。你要求的是"加权",它正在应用"计算优先级值。

任何"计算"基本上是以编程方式应用的条件,以及此处的特定断言" sort"排除" JavaScript跑步者"像mapReduce这样的选项,只是让聚合框架对结果进行其他处理。

对于聚合框架方法,您需要$project计算出的"权重"根据条件对每个匹配的文档:

db.collection.aggregate([
  // Same match conditions to filter
  { "$match": { "$or": [{ "family": 1, }, { "category": 2 }] } },

  // Assign the "weight" based on conditions
  { "$project": {
    "name": 1,
    "family": 1,
    "weight": {
      "$add": [
        { "$cond": {
          "if": { "$eq": [ "$family", 1 ] }, 
          "then": 1,
          "else": 0
        }},
        { "$cond": {
          "if": { "$eq": [ "$category", 2 ] },
          "then": 1,
          "else": 0
        }}
      ] 
    }
  }},

  // Then sort "descending" with highest "weight" on top
  { "$sort": { "weight": -1 } }
])

基本上,您使用$cond来评估返回的文档实际上具有满足您条件的数据的条件,因为在选择中,存在的字段是有效响应。如果条件存在,我们分配一个值,而值不是0

当"两者都是"条件存在$add操作结合权重中的总和。因此,仅符合一个条件的文档只有1,而且两者都有2。如果你退缩了例如"家庭"要获得更大的偏好,那么您将在条件中分配2,从而为您留下可能的文档分数:

  • 3 :适用于系列
  • 类别
  • 2 :仅限家庭
  • 1 :仅限类别

您可以使用$project管道运算符缩短MongoDB 3.4或更高版本中$addFields的语法,这在您拥有" lot"您想要返回的其他文档属性,而无需在$project中列出所有这些属性。

除此之外,数据库服务不允许在"排序"上进行"计算" 。这被认为是"操纵",这是聚合框架的目的。

虽然你可以做同样的"加权"通过在客户端代码中对结果集进行后期处理,这里的问题当然是您想要限制"在" paging"等行动中返回的结果。这是运行服务器上的操作的地方,以及为什么使用聚合框架的原因。