You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按日期+时间排序预订数据?能否通过Mongoose实现?

问题背景

数据模型如下:

{
    time: String,
    date: Date,
    user_id: String
}

获取用户预订数据的接口返回示例:

"reservations": [
    {
        "_id": "63e3bda0a2b3be512b44ba51",
        "time": "10:40",
        "date": "2023-02-06T00:00:00.000Z",
        "user_id": "63d4657708205fda2de700f1"
    },
    {
        "_id": "63e3bda2a2b3be512b44ba56",
        "time": "11:00",
        "date": "2023-02-06T00:00:00.000Z",
        "user_id": "63d4657708205fda2de700f1"
    },
    {
        "_id": "63e3c22bf83f5954d210eb56",
        "time": "13:00",
        "date": "2023-02-06T00:00:00.000Z",
        "user_id": "63d4657708205fda2de700f1"
    },
    {
        "_id": "63e3c224f83f5954d210eb48",
        "time": "10:00",
        "date": "2023-02-10T00:00:00.000Z",
        "user_id": "63d4657708205fda2de700f1"
    },
    {
        "_id": "63e3c228f83f5954d210eb4f",
        "time": "10:00",
        "date": "2023-02-16T00:00:00.000Z",
        "user_id": "63d4657708205fda2de700f1"
    }
]
核心需求

如何对上述预订数据先按日期升序(最早日期在前),同日期下再按时间升序(最早时段在前)排序?能否通过Mongoose实现该排序逻辑?

已尝试的实现方案

先提取所有唯一日期:

const dates = reservations.map((res) => res.date.toISOString());

function onlyUnique(value: any, index: any, self: string | any[]) {
    return self.indexOf(value) === index;
}

var distinctDates = dates.filter(onlyUnique);

接着遍历每个唯一日期,筛选对应预订,将时间转换为分钟数后排序,再合并结果并转换回时间字符串:

for (let i = 0; i < distinctDates.length; i++) {
    const date = new Date(distinctDates[i]);

    let distinctReservations: { _id: any; time: number; date: Date; user_id: string }[] = [];

    for (let j = 0; j < reservations.length; j++) {
        const reservation = reservations[j];

        if (reservation.date.toISOString() === date.toISOString()) {
            distinctReservations.push({
                _id: reservation.id,
                time: hhMMToMinutes(reservation.time),
                date: reservation.date,
                user_id: reservation.user_id
            });
        }
    }
    const sortedByMinutes = distinctReservations.sort((a, b) => a.time - b.time);

    sortedReservationsSlotToMinutes.push(sortedByMinutes);
}

const flated = sortedReservationsSlotToMinutes.flat(2);
const sortedReservations = flated.map((res) => {
    let timeSlot = {
        hour: (res.time / 60).toFixed(),
        minute: ''
    };

    const minuteModule = res.time % 60;
    if (minuteModule) {
        timeSlot.minute = minuteModule.toString();
    } else {
        timeSlot.minute = '00';
    }

    return {
        _id: res._id,
        time: timeSlot.hour + ':' + timeSlot.minute,
        date: res.date,
        user_id: res.user_id
    };
});
return sortedReservations;

希望了解更优的排序方案,尤其是Mongoose层面的实现方式。

解决方案

前端优化排序方案

你当前的实现逻辑可行,但可以简化为一次排序完成,无需拆分日期再合并:

reservations.sort((a, b) => {
    // 先按日期升序比较
    const dateDiff = a.date.getTime() - b.date.getTime();
    if (dateDiff !== 0) {
        return dateDiff;
    }
    // 日期相同时,将时间字符串转为分钟数比较升序
    const convertToMinutes = (timeStr: string) => {
        const [hour, minute] = timeStr.split(':').map(Number);
        return hour * 60 + minute;
    };
    return convertToMinutes(a.time) - convertToMinutes(b.time);
});

该方法直接对原数组排序,先通过时间戳比较日期,日期一致时再转换时间为分钟数排序,代码更简洁高效,避免了多次遍历和数组拆分合并的额外开销。

Mongoose层面实现排序

完全可以在数据库查询阶段完成排序,前端无需处理,还能减少无序数据传输的性能损耗。

基础排序写法

利用Mongoose的sort()方法,直接指定排序字段和顺序:

Reservation.find({ user_id: '目标用户ID' })
  .sort({ date: 1, time: 1 }) // 1代表升序,-1代表降序
  .exec((err, reservations) => {
    // 处理查询结果
  });

由于你的time字段是HH:MM格式的字符串,字符串比较逻辑刚好和时间顺序一致(例如"10:40" < "11:00"),因此直接按字符串排序即可得到正确的时间顺序。

聚合查询写法(复杂场景扩展)

如果后续有更复杂的排序需求,或需要对日期做额外处理,可使用聚合管道:

Reservation.aggregate([
  { $match: { user_id: '目标用户ID' } }, // 过滤目标用户的预订数据
  { $sort: { date: 1, time: 1 } } // 先按日期升序,再按时间升序
])
.exec((err, sortedReservations) => {
  // 处理结果
});

聚合管道方式更灵活,若time字段不是标准HH:MM格式,还可通过$split和$toInt转换后排序:

Reservation.aggregate([
  { $match: { user_id: '目标用户ID' } },
  {
    $addFields: {
      timeMinutes: {
        $sum: [
          { $multiply: [{ $toInt: { $arrayElemAt: [{ $split: ['$time', ':'] }, 0] } }, 60] },
          { $toInt: { $arrayElemAt: [{ $split: ['$time', ':'] }, 1] } }
        ]
      }
    }
  },
  { $sort: { date: 1, timeMinutes: 1 } },
  { $project: { timeMinutes: 0 } } // 移除临时生成的timeMinutes字段
])
.exec((err, sortedReservations) => {
  // 处理结果
});

内容的提问来源于stack exchange,提问作者user17573859

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 02:00:38