【问题标题】:MongoDB sort by relevance (mix $and and $or)MongoDB 按相关性排序(混合 $and 和 $or)
【发布时间】:2017-05-23 19:38:18
【问题描述】:

有 2 个文件,例如:

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

还有一个类似的查询:

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

如何将结果与匹配 2 个条件(“世界”)的结果作为第一个结果进行排序,但仍然让文档仅匹配一个条件作为最后一个结果(“你好”)?

我不能使用默认的 $and 运算符,因为我不会看到不符合这两个条件的“hello”文档。

我看到了聚合如何提供帮助,但对于一个比它需要大量计算的更复杂的示例,我猜这是常见的用例,肯定有一些明显的我遗漏了

【问题讨论】:

    标签: mongodb sorting mongodb-query aggregation-framework


    【解决方案1】:

    你不能用简单的.find() 语句来做那种查询(不是双关语)。您所要求的涉及“加权”,即对值应用“计算的优先级。

    任何带有“计算”的东西基本上都是以编程方式应用的条件,并且此处“排序”的特定断言排除了“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:仅适用于类别

    您可以在 MongoDB 3.4 或更高版本中使用 $addFields 管道运算符缩短 $project 的语法,这在您想要返回“大量”其他文档属性而无需列出时最有用他们都在$project


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

    虽然您可以通过在客户端代码中对结果集进行后处理来执行相同类型的“加权”,但这里的问题当然是您希望“限制”结果以在“分页”等操作中返回。这就是在服务器上运行操作发挥作用的地方,也是您为此使用聚合框架的原因。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-28
      • 2016-06-12
      • 2023-03-22
      • 2016-06-22
      • 1970-01-01
      • 2014-11-08
      相关资源
      最近更新 更多