我想返回节点中匹配对象 id 的上一个对象和下一个对象

Posted

技术标签:

【中文标题】我想返回节点中匹配对象 id 的上一个对象和下一个对象【英文标题】:I will like to return the previous object and the next object of a matching object id in node 【发布时间】: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
]

【问题讨论】:

【参考方案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 类型

以上是关于我想返回节点中匹配对象 id 的上一个对象和下一个对象的主要内容,如果未能解决你的问题,请参考以下文章

具有动画效果的 UIView 上的上一个和下一个实现

SparkSql 查询以从 cassandra 获取定义值的上一行和下一行

Rails获取上一个和下一个活动记录对象的最佳方法

创建链表LinkedList

如何递归搜索对象树并使用 JavaScript/Prototype 1.7 基于键/值返回匹配的对象

如何映射两个数组并将匹配作为按钮返回?