如何按日期+时间排序预订数据?能否通过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
相关产品推荐
相关产品推荐

