【问题标题】:I will like to return the previous object and the next object of a matching object id in node我想返回节点中匹配对象 id 的上一个对象和下一个对象
【发布时间】:2021-04-27 02:50:50
【问题描述】:

请我是节点 js 和 MongoDB 的新手。 当我想通过 id 检索帖子时,我希望能够检索上一篇文章和下一篇文章。 这是我的帖子,它只通过 id 检索当前帖子。

Post.findById(req.params.postId)
    .then((existingpost) => {
        console.log(Post.find(req.params.postId))
      if (existingpost) {
        res.send(existingpost);
      }
      return res.status(404).send({
        message: "Post does not exist with id " + req.params.postId,
      });
    })
    .catch((err) => {
      if (err.kind === "ObjectId") {
        return res.status(404).send({
          message: "Post does not exist with id " + req.params.postId,
        });
      }
      return res.status(500).send({
        message:
          "Some error occurred while retrieving the post with postId " +
          req.params.postId,
      });
    });
};

我目前收到具有这样 id 的对象,这很好。

{
    "_id": "6009f3e294d8a033402a76e7",
    "title": "Covid 19 in Italy",
    "author": "John Doe",
    "createdAt": "2021-01-21T21:36:34.514Z",
    "updatedAt": "2021-01-21T21:36:34.514Z",
    "__v": 0
}

但我很乐意接收当前 id 的对象、前一个对象和下一个对象。 像这样的。

[{
    "_id": "3230g5e382d8a033402a76e7",
    "title": "Effect of Covid on the Economy",
    "author": "John Doe",
    "createdAt": "2021-01-21T21:36:34.514Z",
    "updatedAt": "2021-01-21T21:36:34.514Z",
    "__v": 0
},
{
    "_id": "6009f3e294d8a033402a76e7",
    "title": "Covid 19 in Italy",
    "author": "John Doe",
    "createdAt": "2021-01-21T21:36:34.514Z",
    "updatedAt": "2021-01-21T21:36:34.514Z",
    "__v": 0
},
{
    "_id": "4567hye294d8a033402a76e7",
    "title": "Life after Covid",
    "author": "John Doe",
    "createdAt": "2021-01-21T21:36:34.514Z",
    "updatedAt": "2021-01-21T21:36:34.514Z",
    "__v": 0
}]

【问题讨论】:

    标签: node.js database mongodb mongoose nosql


    【解决方案1】:

    由于它是一个 UUID,因此这种方法可能会对您有所帮助..

    • $sort 按 asc 排序文档
    • $group$unwind 获取索引
    • $facet 将传入数据分类为currentallDocs
    • 我们知道 current 只是一个对象,所以我们使用$unwind 来解构数组
    • 我们已经知道索引,所以我们使用$filter 来获取上一个、当前和下一个使用索引
    • $unwind 解构数组
    • $replaceRoot 使对象到根

    这是脚本

    db.collection.aggregate([
       $sort: { createdAt: 1 } },
      {
        $group: {
          _id: null,
          data: { $push: "$$ROOT"}
        }
      },
      { $unwind: { path: "$data", includeArrayIndex: "index" } },
      {
        $facet: {
          current: [
            { $match: { "data._id": "3230g5e382d8a033402a76e7" } }
          ],
          allDocs: [
            { $match: {} }
          ]
        }
      },
      {
        $unwind: "$current"
      },
      {
        $project: {
          docs: {
            $filter: {
              input: "$allDocs",
              cond: {
                $or: [
                  { $eq: [ "$$this.index", { $subtract: [ "$current.index", 1 ] } ] },
                  { $eq: [ "$$this.index", "$current.index" ] },
                  { $eq: [ "$$this.index", { $add: [ "$current.index", 1 ] } ] }
                ]
              }
            }
          }
        }
      },
      { "$unwind": "$docs" },
      { "$replaceRoot": { "newRoot": "$docs.data" } }
    ])
    

    工作Mongo playground

    有很多方法可以做到这一点,这是其中一种方法。如果你觉得你有很多文档,那么尽量避免使用昂贵的$unwind,在这种情况下你可以尝试使用createdDate而不是索引

    【讨论】:

      【解决方案2】:

      我不确定有没有直接的方法可以做到这一点,你可以尝试聚合,

      使用 UUID 和 CreatedAt:

      • $facet 获取all 中的所有文档,然后按createdAt 升序排序
      • $let 定义变量 states 与开始和总文档,
      • $cond 检查条件,如果输入 uuid 的索引为零,则返回 start: 0total: 2 我们必须从所有数组中切片的文档,否则获取当前索引并减去负 1 和 total: 3
      • in 返回基于 starttotal 的切片文档
      Post.aggregate([
        { $facet: { all: [{ $sort: { createdAt: 1 } }] } },
        {
          $project: {
            result: {
              $let: {
                vars: {
                  states: {
                    $cond: [
                      { $eq: [{ $indexOfArray: ["$all._id", req.params.postId] }, 0] },
                      { start: 0, total: 2 },
                      {
                        start: {
                          $subtract: [{ $indexOfArray: ["$all._id", req.params.postId] }, 1]
                        },
                        total: 3
                      }
                    ]
                  }
                },
                in: { $slice: ["$all", "$$states.start", "$$states.total"] }
              }
            }
          }
        }
      ])
      

      Playground


      使用 ObjectID:

      • 使用mongoose.Types.ObjectId 将您的字符串输入ID req.params.postId 转换为对象ID
      • $facet 分离结果,
      • 首先,$match获取当前和下一个文档,$sort_id按降序排列,$limit2
      • 第二,$match获取上一个文档,$sort_id降序排列,$limit1
      • $project 使用 $concatArrays 连接数组 firstsecond 后得到结果
      req.params.postId = mongoose.Types.ObjectId(req.params.postId);
      Post.aggregate([
        {
          $facet: {
            first: [
              { $match: { _id: { $gte: req.params.postId } } },
              { $sort: { _id: 1 } },
              { $limit: 2 }
            ],
            second: [
              { $match: { _id: { $lt: req.params.postId } } },
              { $sort: { _id: -1 } },
              { $limit: 1 }
            ]
          }
        },
        { $project: { result: { $concatArrays: ["$first", "$second"] } } }
      ])
      

      Playground

      【讨论】:

      • 这是 ObjectId 还是 UUID?如果是 UUID,你会怎么比较!!哦哦可能是一个ObjectId,因为他以字符串的形式发帖,所以我提出了这个问题。
      • OP 在标题中提到了对象 ID,如果他发布字符串,我必须将其与对象一致,但我不知道如何处理 UUID 你有什么线索吗? .
      • 我只是想有索引或(也可能与创建日期一起使用)。工作mongoplayground.net/p/f3Mc6nUk8Qv。可能是一个很长的方法
      • @turivishal 感谢您的代码。上面的id不是结构化id,是uuid。
      • @turivishal 我只是发布了我的答案,因为他说它是一个 uuid。无论两个答案都是正确的,取决于 _id 类型
      猜你喜欢
      • 2014-07-17
      • 1970-01-01
      • 1970-01-01
      • 2013-05-07
      • 2018-04-25
      • 2017-12-03
      • 1970-01-01
      • 1970-01-01
      • 2013-11-12
      相关资源
      最近更新 更多