如何在 Mongoose 的嵌入式文档中检索数组的最后一个对象?

Posted

技术标签:

【中文标题】如何在 Mongoose 的嵌入式文档中检索数组的最后一个对象?【英文标题】:How to retrieve an array's last object in an embedded document in Mongoose? 【发布时间】:2015-11-12 00:36:15 【问题描述】:

我无法编写查询来检索嵌入在 Story 文档中的 Comments 数组的最后一个对象。

当我执行 db.stories.find() 时,我的收藏当前看起来像这样:


"_id" : ObjectId("55d3a39565698bbc68079e31"),
"author" : "Steven Chen",
"link" : "COCO",
"title" : "COCO",
"date" : ISODate("2015-08-18T21:28:53.629Z"),
"comments" : [
    
        "author" : "Steven",
        "text" : "Major",
        "_id" : ObjectId("55d3a39565698bbc68079e32"),
        "date" : ISODate("2015-08-18T21:28:53.632Z")
    ,
    
        "text" : "Canada",
        "author" : "Steven",
        "_id" : ObjectId("55d3a39a65698bbc68079e33"),
        "date" : ISODate("2015-08-18T21:28:58.001Z")
    ,
    
        "text" : "Usa",
        "author" : "Steven",
        "_id" : ObjectId("55d3a39c65698bbc68079e34"),
        "date" : ISODate("2015-08-18T21:29:00.877Z")
    
],
"__v" : 0

我想根据给定 Story 文档的 _id 的日期检索最后一条评论。

我的代码上下文是有一个包含 cmets 列表的 Story 帖子,我想检索最后一条评论并使用 ajax 将其作为 JSON 作为 JSON 发送到我的客户端 JS,以便可以使用最新的/最新评论。

在这种情况下,带有“text: "Usa" 的评论应该是被检索到的评论。

谁能提供正确的方法来做到这一点,如果你能解释为什么会更好?谢谢!

【问题讨论】:

【参考方案1】:

除非您以某种方式进行修改,否则您的“最新”文档将始终位于数组的末尾。当与 $push 运算符一起使用或在客户端代码中使用数组操作方法添加时,将项添加到数组中将始终转到现有项的“末尾”或“追加”。

只有$addToSet 之类的运算符或对$push 操作显式使用修饰符才能改变这一点。

因此,当位于数组的末尾时,您通常想要做的是使用带有负索引的$slice 从数组的“末尾”获取项目:

Model.findById("55d3a39565698bbc68079e31")
    .select( "comments":  "$slice": -1 )
    .exec(function(err,doc) 

    )

如果您确实如前所述修改了数组,其中最新日期不是数组中的最后一个元素,那么您应该在更新时使用$sort 修饰符。如果您要求使用$position 修饰符或使用$addToSet,它通常只会“不合适”。 $position 是故意的,您也不能排序,但您始终可以在像这样的 $addToSet 操作之后对数组进行排序,这会将所有日期按顺序排列,而不会更改数组的任何其他内容:

Model.findByIdAndUpdate("55d3a39565698bbc68079e31",
    "$push":  "comments":  "$each": [], "$sort":  "date": 1    
)

修改数组后,相同的$slice 操作适用于查询,因为数组现在按日期排序。

但是,如果您的意图是让文档中的数组无序,或者按照您想要的其他顺序,但您还想获取最新日期,那么您可以使用 .aggregate()$sort 并检索$last数组入口:

Model.aggregate(
    [
         "$match":  "_id": ObjectID("55d3a39565698bbc68079e31")  ,
         "$unwind": "$comments" ,
         "$sort":  "comments.date": 1  ,
         "$group": 
            "_id": "$_id",
            "author":  "$first": "$author" ,
            "link":  "$first": "$link" ,
            "title":  "$first": "$title" ,
            "date":  "$first": "$date" ,
            "comments":  "$last": "$comments" 
        
    ]
)

注意,当使用 mongoose 的聚合框架时,不会发生在其他查询中发生的 _id“自动转换”(这是设计使然),因此有必要自己转换为 ObjectId 值,如果数据尚未以该形式提供,而是以字符串形式出现。

这些是您从数组中获取最后一个元素(可选地明确排序)的方法。

【讨论】:

谢谢先生!我不知道我必须使用 $slice 来过滤数组。感谢您对聚合和修改的额外解释。这是一个巨大的帮助!【参考方案2】:
db.collection_name.find('title':'COCO','comments': $slice: -1)

【讨论】:

以上是关于如何在 Mongoose 的嵌入式文档中检索数组的最后一个对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 Mongoose 查询对嵌入文档数组进行排序?

mongoose:使用$ pull删除嵌入式文档数组中的值(MongoDB 3.4版本)

如何在嵌入式数组mongodb中查询嵌入式文档

Expressjs Mongoose 发现嵌套的嵌入文档未定义

如何在保存在 Mongoose 之前检查数据库中是不是存在嵌入式文档

如何编写查询来检索每个匹配的子文档数组