Firebase实时数据库中如何按日期型节点Key实现升序排序(客户端展示)
Firebase实时数据库中如何按日期型节点Key实现升序排序(客户端展示)
嘿,我来帮你搞定这个日期排序的问题~你现在遇到的核心卡点是:你的节点Key是DD-MM-YYYY格式的日期字符串,这种格式的字符串按字典序排序(也就是FirebaseorderByKey()的逻辑)和实际的日期顺序不匹配,所以才会出现展示顺序和你预期不符的情况。下面给你两种可行的解决方案:
方案一:客户端拿到数据后手动排序(不用改数据库结构)
你已经在代码里把所有日期Key收集到listeDate数组里了,那我们可以在拿到数据后,把这些字符串转换成标准的日期对象,再按实际日期顺序排序。
注意你要的是「最新日期在上,最旧日期在下」,这其实是降序排序(因为日期数值越大,时间越晚)。修改后的代码如下:
getLogsAction(action) { this.listeDate = []; this.selected = true; console.log('action: ' + action); console.log('tab: ' + this.tabName); console.log('solution: ' + this.service.idSolution); this.afs .list('logs/' + this.tabName + '/' + this.service.idSolution + '/' + action) .snapshotChanges() .subscribe(ok => { this.logsInfos = []; // 先提取所有日期Key this.listeDate = ok.map(elem => elem.key); // 对日期数组进行排序:转换成Date对象后按降序排列 this.listeDate.sort((dateStrA, dateStrB) => { // 拆分DD-MM-YYYY格式的字符串,转成数字 const [dayA, monthA, yearA] = dateStrA.split('-').map(Number); const [dayB, monthB, yearB] = dateStrB.split('-').map(Number); // 创建Date对象(注意JS的Date月份是从0开始的,所以要减1) const dateA = new Date(yearA, monthA - 1, dayA); const dateB = new Date(yearB, monthB - 1, dayB); // 降序排序:用dateB的时间戳减dateA,这样最新的日期会排在前面 return dateB.getTime() - dateA.getTime(); }); // 如果需要同步更新logsInfos(比如要展示日期对应的元数据),可以这样处理 this.logsInfos = this.listeDate.map(dateKey => { const matchedElem = ok.find(item => item.key === dateKey); return { key: dateKey, ...matchedElem.payload.val() }; }); }); }
方案二:修改数据库Key格式,用Firebase原生排序(更高效)
如果你的数据量比较大,客户端排序会消耗额外的性能,更推荐你把日期Key改成YYYY-MM-DD的格式(比如把1-9-2021改成2021-09-01)。这种格式的字符串字典序和实际日期顺序完全一致,你就能直接用Firebase的orderByKey()来排序了。
修改后的代码示例:
getLogsAction(action) { this.listeDate = []; this.selected = true; console.log('action: ' + action); console.log('tab: ' + this.tabName); console.log('solution: ' + this.service.idSolution); this.afs // 这里添加ref参数,用orderByKey()排序 .list('logs/' + this.tabName + '/' + this.service.idSolution + '/' + action, ref => ref.orderByKey()) .snapshotChanges() .subscribe(ok => { // 默认orderByKey()是升序(旧日期在前),如果要最新的在前,直接反转数组就行 const sortedOk = ok.reverse(); this.listeDate = sortedOk.map(elem => elem.key); this.logsInfos = sortedOk.map(elem => ({ key: elem.key, ...elem.payload.val() })); }); }
为什么原来的orderByKey()没用?因为你的日期Key是DD-MM-YYYY且不带前导零,比如1-9-2021和10-1-2022,字符串排序时会按字符逐个比较:1-...的第二个字符是-,ASCII码比10-...里的0小,所以字典序里1-9-2021会排在10-1-2022前面,但实际日期上10-1-2022更晚,自然不符合你的预期啦。
备注:内容来源于stack exchange,提问作者Dorian
相关产品推荐
相关产品推荐

