按日期排序MongoDB查询文档,找出最接近字段的日期

1 投票
2 回答
2263 浏览
提问于 2025-04-18 13:25

我在mongodb里有一堆文档,这些文档记录了过去和即将发生的事件。每个文档里有两个日期字段,分别是'开始'和'结束',它们是bson ISODATE对象。我正在进行一个查询,想找出所有在3天前结束的事件。

db.events.find({'end': {'$gte': datetime.utcnow() - timedelta(days=3)})

我想知道如何根据今天的时间和事件的结束时间来对这个查询的结果进行排序。换句话说,2天前结束的事件应该和2天后即将发生的事件排在差不多的位置。这很重要,因为我不想先显示那些已经发生的事件,也不想先显示那些最远的未来事件。

2 个回答

0

目前看来,MongoDB 还不支持你想要的功能,也就是说,它不能通过函数来进行排序,具体可以查看这个链接

不过,如果你的数据范围总是围绕着今天的话,为什么不考虑每晚更新一个字段,记录当前日期和事件之间的时间差呢?这样你就可以对这个字段建立索引,并进行排序。如果你有多年的数据,可能只想更新最近几周的数据,这样更新的时间就不会随着数据量的增加而变长。

3

如果我理解得没错,你想要按照今天和活动结束时间之间的时间差来排序。所以如果你有一个明天的活动,一个昨天的活动和一个前天的活动,你希望它们的顺序是:

  1. 明天的活动
  2. 昨天的活动
  3. 前天的活动

在这里,明天的活动和昨天的活动可能会根据实际的时间差而互换位置。

这可以通过MongoDB的聚合框架来实现。大致的步骤如下:

  1. 筛选出在某个时间段内结束的文档。
  2. 计算今天和每个活动结束时间之间的差值,并把这个差值放到一个新的字段里(比如叫 timeDelta)。
  3. 因为MongoDB的聚合框架没有绝对值的操作符,所以需要进行一些条件检查,来获取时间差的绝对值,并把它放到另一个新字段里,比如叫 absTimeDelta
  4. 根据 absTimeDelta 来排序。

所以最终的代码大概是这样的:

db.events.aggregate([
    { '$match':
        { 'end':
            { '$gte': datetime.utcnow() - timedelta(days=3) } 
        }
    },
    { '$project':
        {
            'timeDelta': { 
                '$subtract': ['$end', datetime.utcnow()]
            }
        }
    },
    { '$project':
        {               
            'absTimeDelta' : { 
                '$cond' : [
                    { '$lte': ['$timeDelta', 0] },
                    { '$multiply' : ['$timeDelta', -1 ] },
                    '$timeDelta'
                ]
            }
        }
    },
    { '$sort':
        {
            'absTimeDelta' : 1
        }
    }
])

编辑: 在MongoDB 3.2版本中,这个JIRA问题已经修复,引入了 $abs 操作符。这意味着第二个 $project 可以去掉,第一个可以更新。你可以用 $abs: { '$subtract': ['$end', datetime.utcnow()] } 来代替 '$subtract': ['$end', datetime.utcnow()]

撰写回答