使用 Shiny 应用程序保存数据时出现问题

Posted

技术标签:

【中文标题】使用 Shiny 应用程序保存数据时出现问题【英文标题】:Problem when using Shiny app to save the data 【发布时间】:2020-04-15 23:49:21 【问题描述】:

我有一个闪亮的应用程序,它有很多文本输入。我无法正确保存数据部分,例如,保存到本地驱动器。有什么建议么?

     server = function(input, output) 
      values <- reactiveValues()
      #Initial Dataframe 
      values$df <- data.frame(matrix(ncol=4,nrow=0, dimnames=list(NULL, c("Name", "date","Traning",  "certificate"))))

      FinalData =observe(
        if(input$submit >0) 
        isolate(values$df <- rbind(values$df,data.frame("name" = input$name,"date" = input$date, 
                           "training" = input$training, "certificate" = input$certificate)))
    # saveRDS(values$df)
    # saveRDS(FinalData)
                   )

    #display the inputs
     output$Combined_table = renderDataTable(values$df)

)

【问题讨论】:

【参考方案1】:

试试这个演示:

library(shiny)
.log <- function(...) message(format(Sys.time(), format = "[ %H:%M:%S ]"), " ", ...)
.read <- function(path) if (file.exists(path)) return(readRDS(path))
shinyApp(
  ui = fluidPage(
    textInput("txt", "Text: "),
    actionButton("btn", "Submit"),
    tableOutput("tbl")
  ),
  server = function(input, output, session) 
    .log("hello world")
    rv <- reactiveValues()
    rv$df <- data.frame(row = 0L, word = "a", stringsAsFactors = FALSE)[0,]
    observeEvent(req(input$btn), 
      .log("submit!")
      rv$df <- rbind(rv$df,
                     data.frame(row = input$btn, word = input$txt,
                                stringsAsFactors = FALSE))
      .log("saveRDS: ", nrow(rv$df))
      saveRDS(rv$df, "local.rds")
    )
    filedata <- reactiveFileReader(1000, session, "local.rds", .read)
    output$tbl <- renderTable(filedata())
  
)

这个应用程序的工程:

我像你一样使用reactiveValues,以保留内存中的数据。 (注意:从长远来看,向帧迭代添加行是不好的。如果这是少量添加,那么你可能没问题,但它的扩展性很差。每次添加一行时,它都会复制整个帧,内存消耗翻倍。) 我用零行帧预先填充$df,仅用于格式化。这里没什么特别的。 observeobserveEvent 不返回您感兴趣的内容,它应该完全由 side-effect 操作。它确实返回了一些东西,但它真的只对 shiny 内部有意义。 saveRDS 和你一样,没什么花哨的,但它有效。 我添加了shiny::reactiveFileReader 以证明文件正在被保存。当闪亮表显示更新时,这是因为(1)数据已添加到底层框架; (2) 帧被保存到"local.rds"文件中;然后 (3) reactiveFileReader 注意到底层文件存在并且已经更改,导致 (4) 它调用我的 .read 函数来读取内容并将其作为反应数据返回到 filedata。这个块一般来说是完全没有必要的,这里只是为了演示。 我为这个reactiveFileReader 创建了一个函数.read,它对不存在的文件具有弹性。如果文件不存在,它会隐形返回NULL。可能有更好的方法来做到这一点。

【讨论】:

感谢 r2evans。我想知道将应用程序上传到服务器时它是否会工作,特别是在同一情况下,有些人可能会同时使用该应用程序。一个人的输入是否有可能覆盖其他人的输入?让我试试你的代码。 是的,这是可能的。听起来您需要诸如数据库或 redis(或类似)服务器之类的东西来处理并发访问。如果你一次只说几个,你也许可以使用 sqlite(或duckdb)来代替。 我一直在阅读 Deam Attali 的“Persistent data storage with Shiny”。他提到了一些远程解决方案。我不知道它是否适用于我有权访问的 microsoft SQL 服务器 有了可用的 DBMS,您当然可以让它更适合多个用户。我建议您创建一个包含所有信息的表(可能还有一个 Id 字段,其他字段可能有用)和 DBI::dbWriteTable(..., append=TRUE) 该信息。如果您需要定期检查,而不是 reactiveFileReader,那么 observe(..., invalidateLater(3000);) 将每 3 秒重新触发一次块(根据您的需要调整,意识到它每次都在运行查询,绝对是正确和错误的方法)。 我正在寻找“保证”。欣赏!

以上是关于使用 Shiny 应用程序保存数据时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

部署 R Shiny 应用程序时加载包时出现问题

保存数据时出现问题

从命令行守护程​​序使用 MLMediaLibrary 时出现 XPC 错误

RODBCext:使用 sqlExecute() 时出现 SQL 42000 402 错误

在 ShinyApp 中使用下载处理程序下载数据时出现问题

保存非英文字符时出现问题