Fetch immediate next and previous documents based on conditions in MongoDB

Abh*_*jit 3 mongoose mongodb mongodb-query aggregation-framework

Background

I have the following collection:

article {
  title: String,
  slug: String,
  published_at: Date,
  ...
}
Run Code Online (Sandbox Code Playgroud)

MongoDB version: 4.4.10

The problem

Given an article, I want to fetch the immediate next and previous articles depending on the published_at field of that article.

假设我有一篇带有published_atas的文章100。有很多文章的内容published_at小于100,也有很多文章的内容published_at大于100。我希望管道/查询仅获取具有或或最接近可能published_at值的文章。99101

尝试

这是我的聚合管道:

const article = await db.article.findOne({ ... });

const nextAndPrev = db.article.aggregate([
    {
        $match: {
            $or: [
                {
                    published_at: { $lt: article.published_at },
                    published_at: { $gt: article.published_at },
                },
            ],
        },
    },
    {
        $project: { slug: 1, title: 1 },
    },
    {
        $limit: 2,
    },
]);
Run Code Online (Sandbox Code Playgroud)

它给出了错误的结果(所提供的文章之后的两篇文章),这是预期的,因为我知道它是不正确的。

可能的解决方案

  • 我可以使用两个单独的findOne查询轻松完成此操作,如下所示:

    const next = await db.article.findOne({ published_at: { $gt: article.published_at } });
    const prev = await db.article.findOne({ published_at: { $lt: article.published_at } });
    
    Run Code Online (Sandbox Code Playgroud)

    但我很好奇是否有任何可用的方法可以在一次数据库访问中完成此操作。

  • 如果我对所有文章进行排序,将其偏移到时间戳,并提取上一个和下一个条目,这可能会起作用。我不知道语法。

ray*_*ray 6

从 MongoDB v5.0 开始,

您可以$setWindowFields根据特定的排序/排名来获取立即的上一个/下一个文档。

您可以_id通过操作该字段来获取当前和下一个文档的内容documents: [<prev offset>, <next offset>]。类似地,对于 OP 的场景,一次获取上一个、当前和下一个文档将是 [-1, 1]。执行通过存储在数组中$lookup取回文档。_idnearIds

{
    "$setWindowFields": {
      "partitionBy": null,
      "sortBy": {
        "published_at": 1
      },
      "output": {
        nearIds: {
          $addToSet: "$_id",
          window: {
            documents: [
              -1,
              1
            ]
          }
        }
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

这是Mongo游乐场供您参考。