firebase - 按 desc 排序的时间范围内的 Firebase 查询值
问题描述
我的目标: 我想从按喜欢(降序)排序的无限集合中检索项目。我还想按日期和结果计数限制这些结果,例如前 10 名。
我无法以一种很好的方式妥善处理这个案子。这是我到目前为止得到的,但我只想要前 10 个结果,并且缺少这个限制。如果我limit()
在查询中放置一个,我不会得到正确的结果。
Timestamp get timeLimit {
final limit = DateTime.now().subtract(const Duration(days: 30));
return Timestamp.fromDate(limit);
}
QuerySnapshot snapshot =
await FirebaseFirestore.instance
.collection('data')
.where('date', isGreaterThanOrEqualTo: timeLimit)
.orderBy('date', descending: true)
.get();
snapshot.docs.forEach((document) {
Data data = Data.fromJson(document.data());
resultList.add(data);
resultList.sort((a, b) => b.likes.compareTo(a.likes));
});
解决方案
您正在达到 Cloud Firestore 的限制。如果您有一个具有范围比较(<、<=、>、>=)的过滤器,则您的第一个排序必须在同一字段上。[参考:https://cloud.google.com/firestore/docs/query-data/order-limit-data]
在您的情况下,第二个 orderBy (on likes
) 只会在完全相同的组中产生影响date
,这将是非常无用的。
头脑风暴解决方案。
(欢迎任何建议!)
如果您的目标是跟踪每日/每周/每月 TOP 10,您可能应该在 Firestore 中维护该列表,而不是计算每个访问者的列表。
您可以让每个 [待定义的持续时间] 运行一个云函数来重置 TOP 10 列表。
这是有代价的,但read
对于每位游客来说,运营成本会大大降低。
!!!注意,以下内容未经测试。
这样的函数可以写成:
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.computeTopTenLists = functions.pubsub.schedule('every 2 hours').onRun((context) => {
var millisecondsInOneDay = 24 * 60 * 60 * 1000;
var dailyStart = new Date(Date.now() - millisecondsInOneDay);
var weeklyStart = new Date(Date.now() - 7 * millisecondsInOneDay);
var monthlyStart = new Date(Date.now() - 30 * millisecondsInOneDay);
date.setDate(date.getDate() - 7);
// Top 10 list (sorted by likes, descending)
var dailyTopTen = [];
var weeklyTopTen = [];
var monthlyTopTen = [];
db.collection('data').where("date", ">=", monthlyStart ).get().then((querySnapshot) => {
[
{ list: dailyTopTen, start: dailyStart },
{ list: weeklyTopTen, start: weeklyStart },
{ list: monthlyTopTen, start: monthlyStart },
].forEach((curr) => {
curr.list.push(querySnapshot[0].data());
querySnapshot.slice(1).forEach((doc) => {
var data = doc.data();
data['id'] = doc.id;
if (data['date'] > curr.start && data['likes'] > curr.list[curr.list.length-1]) {
curr.list.push(data);
curr.list.sort((a, b) => (a.likes > b.likes ? -1 : 1));
curr.list = curr.list.slice(0, 10);
}
});
});
})
db.collection('top-ten').document('lists').set({
daily: dailyTopTen.map(data => ({id: data['id'], title: data['title']})),
weekly: weeklyTopTen.map(data => ({id: data['id'], title: data['title']})),
monthlyly: monthlyTopTen.map(data => ({id: data['id'], title: data['title']})),
});
return null;
});
您只需阅读一份文档即可获得三个 Top 10 列表。
推荐阅读
- css - 尝试在 Bulma CSS 上实现砌体
- scala - 需要来自邮递员 curl url 的等效 gatling scala 代码
- unity3d - 如何在 Arcore(unity) 中获得 vuforia 云识别类功能
- azure - Azure App 服务重新启动是否也会重新启动 Web 作业?
- hibernate - Spring Boot JPA Hibernate 父/子/孙
- python - DateTimeField 使用日历输入而不是文本
- javascript - 创建产品页面的更好或推荐方式
- r - 将数据框 IN R 扩展为更大的数据框
- json - 反序列化 json 在 xamarin 表单中显示 null
- flutter - Flutter ReorderableListView 不适用于 TextFields