具有复杂排序顺序的Mongo查询

时间:2017-07-24 09:49:30

标签: mongodb-query

我对mongo很新,我正在尝试研究如何对查询结果应用复杂的排序。我收集了一些帖子,其中包含“用户”或“提升”类型,并且都有创建日期。我需要做的是按创建日期排序列表,但确保两个最近推荐的帖子位于列表的顶部,无论它们何时创建。如果可能的话,我更愿意在mongo中使用现有的分页解决方案。

查找前两个推广帖子很简单:

db.example.find({type:“pro”})。sort({create_dt:1})。limitit(2)

但是,我是否需要对所有重新发布的帖子(不包括原来的前两个)进行聚合,并以某种方式加入两组结果?或者有没有办法动态标记前两个提升的帖子,然后使用标签订购整个列表?

感谢。

1 个答案:

答案 0 :(得分:1)

Phew ......这花了我一段时间,结果确实不是特别令人满意(但是?)。不过,它应该可行 - 它确实在我的测试数据集上做了,我试图从你上面的输入中推断出来。我很乐意根据要求更详细地解释各个步骤。与MongoDB聚合一样,您可以通过从查询结束开始逐步减少投影阶段来了解正在发生的事情。

db.restaurants.aggregate(
  {
    $match: {/* for optimization only: any potentially reasonable filters to speed up the query */}
  },
  {
    $sort:
    {
      "type": 1, // 'promoted' first and then 'user' posts
      "create_dt": -1 // the latest posts first
    }
  },
  {
    $group:
    {
      _id:  "$type", // two groups, one for 'promoted' posts & one for type 'user'
      items: { $push: "$$ROOT" } // remember the entire document
    }
  },
  {
    $project:
    {
      "items":
      {
        $zip: // we use $zip to reduce the number of items per group...
        {
          inputs:
          [
            {
              $cond:
              [
                { $eq: ["$_id", "promoted"] }, // ...depending on the type...
                [1,2], //...to 2 items in the case of 'promoted' type posts
                { $range: [ 1, 100, 1 ] } //...and to 100 items - change if needed - for 'user' type posts
              ]
            }
            ,
            "$items"
          ]
        }
      }
    }
  }
  ,
  {
    $unwind:
    {
      path: "$items", // first level of unwinds --> we get an array output still from the $zip operation
    }
  },
  {
    $unwind:
    {
      path: "$items", // second level of unwinds - we flatten everything to the lowest level
    }
  },
  {
    $match:
    {
      "items": { $type: 3 } // get rid of the index element that got created in the $zip stage, only keep objects
    }
  },
  {
    $replaceRoot: { newRoot: "$items" } // make sure we get a nice list of posts back
  }
)