javascript - 基于多个时间戳作为二级索引的 RethinkDB 查询
问题描述
我有一个带有“事件”表的 RethinkDB,每个事件都有一个“来自”和一个“到”列,两者都是时间戳。
我想主要通过返回时间窗口中“活动”的所有事件来查询此表,这意味着从列在时间窗口结束之前,结束列在时间窗口开始之后(开始时间窗口是当前时间,时间窗口结束是当前时间 + 2 小时)。出于这个原因,我在两列上都创建了二级索引。
理想情况下,我希望将其作为单个更改源接收,包括实时事件的任何更改,并选择随着时间的推移而变得活跃的事件,但据我所知,这是不可能的,因为根据文档“命令now() 在服务器收到查询时计算一次”(如果我错了,请纠正我),所以我将求助于每小时创建一个新的 changefeed 来查询当前时间 2 小时内的活动事件。
现在我首先想到我会像这样在调用之间使用两个
let currentEndpoint = moment().add(2, 'hours');
// query for active events
r
.table('events')
// event start is before end of window
.between(new Date(1), currentEndpoint, {index: 'from'})
// event end is after current time
.between(new Date(), r.epochTime(1900266776))
.run(connection)
.then(res => {
console.log(res)
})
.catch(e => {
console.error(e);
})
这显然是不允许的:ReqlQueryLogicError: Cannot perform multiple BETWEENs on the same tabl
我了解如何很容易地使用 filter 命令执行此操作,但由于这是我想要查询表的主要方式,我认为使用索引会更好,有没有办法创建这个查询?
视觉示例
event2
\
_____\______
/ \
time: ---->---->---->---->---->---->---->---->---->---->----> ...
\__/ \__/ / \__/
event1___/ event3__/ / event5__/
event4_/
^ ^
query window: |______________|
expected results: [ event2, event3 ]
可重现的问题
创建一个events
表 -
r.tableCreate("events");
// { tables_created: 1, ... }
添加一些事件。为了概念上的简单性,我们只关心year
、month
和day
。以更精细的时间解决问题,例如hours
, 或minutes
实际上是相同的
r.table("events").insert([
{ name: "fishing tourney"
, from: r.time(2020, 1, 11, "Z")
, to: r.time(2020, 1, 12, "Z")
}
, { name: "cherry blossom"
, from: r.time(2020, 4, 1, "Z")
, to: r.time(2020, 4, 10, "Z")
}
, { name: "fishing tourney"
, from: r.time(2020, 4, 11, "Z")
, to: r.time(2020, 4, 12, "Z")
}
, { name: "bunny day"
, from: r.time(2020, 4, 1, "Z")
, to: r.time(2020, 4, 12, "Z")
}
, { name: "fishing tourney"
, from: r.time(2020, 7, 11, "Z")
, to: r.time(2020, 7, 12, "Z")
}
]);
// { inserted: 5, generated_keys: [ ... ], ... }
创建某种二级索引-
r.table("events").indexCreate(
"event_window",
???
);
给定日期范围,获取具有相交事件窗口的所有事件 -
const start = r.time(2020, 4, 8, "Z"); // April 8, 2020
const end = start.add(3 * 24 * 60 * 60); // April 11, 2020, 3 days later
// filter it?
r.table("events").filter(???)...
// use .between somehow?
r.table("events").between(???, ???, { index: "event_window" })
// some other technique?
r.table("events").eqJoin(???)
r.table("events").???
2020 年 4月 8 日至 2020 年4月 11 日重叠的活动-
// expected output
[ { name: "cherry blossom"
, from: r.time(2020, 4, 1, "Z")
, to: r.time(2020, 4, 10, "Z")
}
, { name: "fishing tourney"
, from: r.time(2020, 4, 11, "Z")
, to: r.time(2020, 4, 12, "Z")
}
]
解决方案
您将在结果集中返回的事件至少属于以下一组:
- 在查询窗口中结束的所有事件。
- 在查询窗口中开始的所有事件。
(在查询窗口内开始和结束的事件属于这两个集合)
如果您索引您的from
和to
属性,您可以查询All events that ended in query window
,并将其与 结合All events that started in query window
。您仍然可以为每组事件使用正确的索引。请记住对碰巧落入两个集合的事件进行重复数据删除。
r.table("events").between(r.time(2020, 4, 8, "Z"), r.time(2020, 4, 11, "Z"), { index: "from", rightBound: "closed" }).union(
r.table("events").between(r.time(2020, 4, 8, "Z"), r.time(2020, 4, 11, "Z"), { index: "to" })
).distinct()
我不能说这是惯用的还是实现这一点的最佳方式,但我过去不得不使用类似的东西。
推荐阅读
- java - 升级到 macOS Big Sur 后无法启动 Neo4j 控制台应用程序
- python - Python - 计算两个不同列中相同值的出现次数
- sql - 如何插入 table1 列,其中另一个 table1 列与 table2 列相同
- python - 如何用python估计硬币翻转的概率?
- c++ - 当我们尝试获取 NULL 字符串的长度时,为什么会出现运行时错误?
- ruby - 找出一天中注册人数最多的时间
- react-native - 当 Text 组件被另一个 Text 组件包裹时,ellipsizeMode 不起作用
- vulkan - 更新加速结构时的验证错误(VK_KHR_ray_tracing)
- java - Gradle 和 API 依赖
- javascript - 如何在 svelte 的 javascript 中单击按钮时调用异步函数?