【问题标题】:Retrieve sub-documents that match with maximum value in the array检索与数组中最大值匹配的子文档
【发布时间】:2016-10-02 08:33:19
【问题描述】:

我在mongodb中有如下数据结构

[
    {
        "id" : "unique id 1",
        "timeStamp" : "timeStamp",
        "topicInfo" : [
            { 
                topic : "topic1", 
                offset : "offset number",
                time: 1464875267637
            },
            { 
                topic : "topic2", 
                offset : "offset number",
                time: 1464875269709
            },
            { 
                topic : "topic3", 
                offset : "offset number",
                time : 1464875270849
            }
       ]
   },
   {
       "id" : "unique id 2",
       "timeStamp" : "timeStamp",
       "topicInfo" : [
           { 
               topic : "15", 
               offset : "offset number",
               time : 1464875271884
           },
           { 
               topic : "topic2", 
               offset : "offset number",
               time : 1464875273887
           },
           { 
               topic : "topic3", 
               offset : "offset number",
               time : 1464875272848
           }
       ]
   }
 ]

现在我想找到所有具有名为“topic2”的主题的条目,并且与“topicInfo”数组中的其他对象相比,时间的值是最大值。我还想按“时间戳”对它们进行排序。从示例代码中,查询应该返回第二个对象。我无法编写查询任何帮助将不胜感激。

【问题讨论】:

  • 为什么你的文档中有“时间”字符串?
  • 对不起,我正在编辑它。实际上是以毫秒为单位的时间。

标签: node.js mongodb mongodb-query aggregation-framework


【解决方案1】:

执行此操作的最佳方法是在 MongoDB 3.2 或更高版本中。我们需要$project 我们的文档并使用$filter 运算符返回与我们的条件匹配的“topicInfo”数组的子集。而从 MongoDB3.2 开始,我们可以在 $project 阶段中​​使用 $max condition 表达式,并对返回值进行逻辑运算。

管道中的最后一个阶段是$match 阶段,您可以使用$exists 元素查询运算符和dot notation 访问数组中的第一个元素来过滤掉那些具有空“topicInfo”的文档。这也减少了通过网络发送的数据量以及用于在客户端解码文档的时间和内存。

db.collection.aggregate([
    { "$project": { 
        "topicInfo": { 
            "$filter": { 
                "input": "$topicInfo", 
                "as": "t", 
                "cond": { 
                    "$and": [ 
                        { "$eq": [ "$$t.topic", "topic2"] }, 
                        { "$eq": [ "$$t.time", { "$max": "$topicInfo.time" } ] }
                    ] 
                } 
            } 
        } 
    }},
    { "$match": { "topicInfo.0": { "$exists": true } } }
])

【讨论】:

  • 它返回所有但预期的对象的 topicInfo 数组非空,非预期的对象为空。我可以通过应用层操作从那里弄清楚。然而,这是最佳解决方案还是有办法只过滤预期的条目。
  • @MustafaMamun 是的,这是最佳方式。我已经更新了我的答案,现在只选择那些具有非空数组的文档。
【解决方案2】:

你可以用这样的聚合框架来做到这一点:

db.test.aggregate(
    { $unwind: '$topicInfo' }, 
    { $match: { 'topicInfo.topic': 'topic2' } }, 
    { $group: { 
        _id: '$id', 
        timestamp: { $first: '$timestamp' }, 
        time: { $max: '$topicInfo.time' } } 
     }, 
     { $sort: { timestamp: 1 } }).pretty()

【讨论】:

    猜你喜欢
    • 2014-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-15
    • 2019-01-16
    相关资源
    最近更新 更多