如何在实时数据框中保存 sql 数据库?闪亮的
Posted
技术标签:
【中文标题】如何在实时数据框中保存 sql 数据库?闪亮的【英文标题】:how to save a sql database in a real time dataframe? shiny 【发布时间】:2020-09-17 17:44:48 【问题描述】:1.问题:
我正在使用一个 sql 数据库,该数据库由我的闪亮应用程序和另一个闪亮的应用程序更新。我使用df=isolate(reactivePoll ())
能够对数据帧进行子集化,因为 reactivePoll 会生成 function 结果,但是isolate()
方法有一个严重的问题:它只在闪亮的应用程序打开时更新数据帧,它只运行一次。
如何实时更新数据框对象并能够对其进行子集化?没有错误:Error in: object of type 'closure' is not subsettable
或 Warning: Error in .getReactiveEnvironment()$currentContext: Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
例如,reactivepoll 函数在渲染函数中可以很好地实时显示表格,但是如何实时更新 data.frame?能够对其进行子集化 df$col1 df$col2 等?
server(input,output,session)
df=reactivePoll(intervalMillis = 2000,session, checkFunc = function()
QUERY1= "SELECT * FROM table"
df_rs = dbSendQuery(storiesDb,QUERY1)
dbFetch(df_rs),
valueFunc =function ()
QUERY1= "SELECT * FROM table"
df_rs = dbSendQuery(storiesDb,QUERY1)
dbFetch(df_rs)
)
dataframe= isolate(df()) # this approach makes the dataframe update only when the shiny app open.
尝试
1-我已经尝试使用dataframe=reactive(df ())
,但是当我尝试对 dataframe$col1 进行子集设置时出现错误:Error in: object of type 'closure' is not subsettable
2-我已经尝试使用dataframe=df ()
,但报错:Error in .getReactiveEnvironment()$currentContext: Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
【问题讨论】:
错误和您的代码表明您正在尝试错误地访问df()
。它必须在reactive
、eventReactive
、observe
、observeEvent
或render*
函数之一内。对于任何反应式表达式都是如此,而不仅仅是从 reactivePoll
返回的表达式。
例如,如果你这样做df2 <- reactive( head(df(), 1) )
就可以正常工作(并不是说这是有意义的事情)。
感谢您的回答,我尝试了这个并给出了以下错误:警告:错误:“闭包”类型的对象不是子表 53:ifelse [# 267] 52:服务器 [# 267]错误:“闭包”类型的对象不是子集
“闭包”实际上是一个函数,所以你不小心做了reactive( head(df, 1) )
?
不,我没有忘记()
【参考方案1】:
我认为您最好使用invalidateLater
而不是reactivePoll
。后者旨在使用一个
相对便宜的“检查”功能和更昂贵的值检索功能
在您的情况下,无论如何,您打算每 2 秒运行一次查询。不需要“检查”。
此外,shiny
中的 reactive*
函数往往是 惰性的(如果没有任何依赖,它将永远不会触发),而 observe*
函数更贪婪(并且不管依赖项)。
这个怎么样?
dat <- reactiveValue(NULL)
observe(
invalidateLater(2000)
QUERY1 = "SELECT * FROM table"
ret <- dbGetQuery(storiesDb, QUERY1)
dat(ret)
)
output$tbl <- renderDataTable(
dat()
)
您可能只想考虑下载最近数据,具体取决于该表的架构。例如,如果有一个时间戳(例如,Created
表示数据何时插入到表中),那么也许您可以使用类似
dat <- reactiveValue(NULL)
observeEvent(invalidateLater(2000),
olddat <- dat()
latest <- max(c(as.POSIXct("1900-01-01"), olddat$Created), na.rm = TRUE)
QUERY1 = "SELECT * FROM table t where t.Created > ?"
newdat <- dbGetQuery(storiesDb, QUERY1, params = list(latest))
if (NROW(newdat) > 0)
newdat <- rbind(olddat, newdat)
dat(newdat)
)
output$tbl <- renderDataTable(
dat()
)
根据您的架构,您的表中可能还有一个Modified
字段,其中Created
表示首次添加的时间,Modified
表示上次更改的时间。在这种情况下,您可能需要检查这两个字段的新近度。 (也许我现在超前了。)
然而,您可以使用reactivePoll
执行“快速”检查功能和“较慢”值功能,可能类似于:
df <- reactivePoll(2000, session,
checkFunc = function()
dbGetQuery(storiesDb, "select count(*) as n from table")
,
valueFunc = function()
dbGetQuery(storiesDb, "select * from table")
)
output$tbl <- renderDataTable(
df()
)
这个想法(使用valueFunc
来计算行数)也可以适用于利用Created
和Modified
...事实上,如果你有这些字段中的一个或两个,大多数表将是索引/优化,以便查询max(Created)
非常快。当然,获取表的行数通常会优化为近乎立即的查询,因此您可能会从一些内部基准测试和/或与 DBA 的讨论中受益。
【讨论】:
【参考方案2】:reactivePoll
返回一个响应式对象,因此您只能在响应式上下文中访问它。如果要对其进行子集化,可以使用以下编码样式:
df_subset <- reactive(
df()[, input$selected_col]
)
这再次返回一个反应对象,所以你可以显示它:
output$table <- renderTable(
df_subset()
)
如果您想在df_subset
发生更改时对数据库进行更改,您可以使用observeEvent
:
observeEvent(subset_df(),
# code to change the DB
)
【讨论】:
以上是关于如何在实时数据框中保存 sql 数据库?闪亮的的主要内容,如果未能解决你的问题,请参考以下文章