How can I update data from SQL in R? - r

I have a sample database in SQL and an RShiny app. I have a connection to the database and can retrieve the data.
I cannot get the Shiny app to update when new data is adding to the database. I can see how it works with CSV files but am not able to find anything similar for SQL.
This is my code:
library(RODBC)
library(shiny)
dbCon <- odbcConnect("SQL")
df <- sqlFetch(dbCon, "Test")
odbcClose(dbCon)
page_1 <- tabPanel(
tableOutput('table')
)
ui <- navbarPage(
page_1
)
server <- function(input, output, session) {
output$table <- renderTable('table')
myFile <- Q1
data <- reactivePoll(1000, session,
# Returns the time the file was last modified (read that to be SAVED))
checkFunc = function() {
if (file.exists(myFile))
file.info(myFile)$mtime[1]
else
shinyalert(title = "file", text = "There is no such file")
},
# Get file content
valueFunc = function() {
dbCon <- odbcConnect("SQL")
df <- sqlFetch(dbCon, "Test")
odbcClose(dbCon)
output$table <- renderTable('table')
}
)
}
shinyApp(ui = ui, server = server)
I believe I have two problems:
Q1. What should the path for 'myFile' be?
Q2. How should I write the code in the checkFunc function to see if the data has been updated?
Thanks

Related

How to get a path to generate dataset as an input in shiny

I'm new to shiny, so don't mind me if my question is simple.
I want to take a path as an input from the user and generate the data frame. I've done this so far:
library(shiny)
ui <- fluidPage(
textInput("data_path", "Please enter the path of your data: ")
tableOutput("data_glimpse")
)
server <- function(input, output){
data <- read.csv(input$data_path)
output$data_glimpse <- renderTable({
glimpse(data)
})
}
shinyApp(ui = ui, server = server)
But it's not working right. I don't get any pages to enter my path!
Any help?
I think it is easier to upload the file directly. But if you want to keep this structure, you can try the following. To make it work you have to add to your path the name of the file plus .csv, e.g. /sample.csv
library(shiny)
ui <- fluidPage(
textInput("data_path", "Please enter the path of your data: "),
tableOutput("data_glimpse")
)
server <- function(input, output){
dataTable <- reactive({
data <- read.csv(input$data_path)
})
output$data_glimpse <- renderTable({
dplyr::glimpse(dataTable())
})
}
shinyApp(ui = ui, server = server)

Downloading the outputs of a reactive table in R shiny

I have an R shiny app that gets a .csv import from a user and searches the imported data across a built-in data frame, then gives the % match in the output. The UI is very simple, with a few different inputs (import .csv, a slider, and some radio buttons). What I want is to be able to take the reactive table output and print this to a .csv that the user can download to their machine. The server side of the app looks something like this:
server <- function(input, output){
rvals <- reactiveValues()
observeEvent(input$file_1,{
req(input$file_1)
rvals$csv <<- read.csv(input$file_1$datapath, header = TRUE)
#some data processing here
})
output$contents <- renderTable({
if(input$select == 1){
x <- function
}else if(input$select == 2){
x <- function
}else if(input$select == 3){x <- function}
#some more data processing and formatting here
return(x)
},digits = 4)
}
I would like to have the data table x be able to become a .csv that can be downloaded by clicking a download button. In the server, I added the following code, but when I try to download the data it just downloads a blank file and says "SERVER ERROR" in my downloads manager on my machine.
output$downloadData <- downloadHandler(
filename = "thename.csv",
content = function(file){
write.csv(x, file)
}
In the console I also get the error message:
Warning: Error in is.data.frame: object 'x' not found [No stack trace available]
The object you create inside the expression of renderTable is not available outside of it. Instead you could assign it to the reactive values you set up. Below is a working example (note that I have tried to replicate your code so the data will not be available until you click on "Upload CSV", which here just calls mtcars).
library(shiny)
ui = fluidPage(
sidebarPanel(
actionButton(inputId = "uploadCsv", label = "Upload CSV:", icon = icon("upload")),
selectInput(inputId = "preProc", label = "Pre-processing", choices = c("Mean"=1,"Sum"=2)),
downloadButton("downloadData", label = "Download table")
),
mainPanel(
h4("My table:"),
tableOutput("contents")
)
)
server <- function(input, output) {
rvals <- reactiveValues(
csv=NULL,
x=NULL
)
observeEvent(input$uploadCsv,{
rvals$csv <- mtcars # using example data since I don't have your .csv
# rvals$csv <- read.csv(input$file_1$datapath, header = TRUE)
#some data processing here
})
output$contents <- renderTable({
# Assuing the below are functions applied to your data
req(
input$preProc,
!is.null(rvals$csv)
)
if(input$preProc == 1){
rvals$x <- data.frame(t(colMeans(mtcars)))
}else {
rvals$x <- data.frame(t(colSums(mtcars)))
}
return(rvals$x)
},digits = 4)
output$downloadData <- downloadHandler(
filename = "myFile.csv",
content = function(file){
write.csv(rvals$x, file)
}
)
}
shinyApp(ui,server)
EventReactive already outputs a reactive value, you don't need to create an extra reactiveVal, see example below :
library(shiny)
# Define UI
ui <- fluidPage(
# Application title
titlePanel("Test"),
mainPanel(
actionButton("show", "Download"),
textOutput("result")
)
)
server <- function(input, output) {
csvfile <- eventReactive(req(input$show), ignoreNULL = T, {
"Content of file"
})
output$result <- reactive(
paste("result : ",csvfile()))
}
# Run the application
shinyApp(ui = ui, server = server)
I would also avoid to use <<-operator in a reactive expression.

Read json file continuously

I want to read a json file continuously, e.g. every 1000 ms.
One option my be reactiveFileReader
reactiveFileReader(intervalMillis, session, filePath, readFunc, ...)
described here.
This function seems only working with csv files and not for json files:
file_data <- reactiveFileReader(intervalMillis = 1000, NULL, filePath = json_path, readFunc = read.json)
observe({
View(file_data())
})
Error in View : object read.json not found
With reactivePoll like here:
getJsonData <- reactivePoll(1000, session,
checkFunc = function() {
if (file.exists(path))
file.info(path)$mtime[1]
else
""
},
valueFunc = function() {
read_json(path)
}
I get nearly what I want, but this function is not working in my context. How do I force the program to read the file every second and not only when the content of the file is changing?
Are there other possibilities I not have thought about yet?
In your first way, you wrote read.json instead of read_json.
With your second way, you could replace file.info(path)$mtime[1] with runif(1, 0, 1e6). You would be very unlucky if runif returns the same number two consecutive times.
Finally, a third way could be:
server <- function(input, output, session){
autoInvalidate <- reactiveTimer(1000)
getJsonData <- reactive({
autoInvalidate()
read_json("path/to/file.json")
})
}
Here is a reprex on how to use reactiveFileReader with a json file.
I used a future to detach the writing process from the shiny session - you can simply replace this with your json input.
library(shiny)
library(jsonlite)
library(datasets)
library(promises)
library(future)
plan(multisession(workers = 2))
ui <- fluidPage(
uiOutput("printResult")
)
server <- function(input, output, session) {
json_path <- tempfile(fileext = ".json")
write_json(NULL, json_path)
# async file writing process
future({
for(i in seq_len(nrow(iris))){
Sys.sleep(1)
write_json(iris[i,], json_path)
}
})
file_data <- reactiveFileReader(intervalMillis = 1000, NULL, filePath = json_path, readFunc = read_json)
output$printResult <- renderUI({
req(file_data())
})
}
shinyApp(ui, server)

How can I prevent RMySQL errors and show to user in Shiny?

I have a Shiny App that executes a query to a MySQL database like this example:
UI
textAreaInput("query")
SERVER
data <- reactive({
df<-dbGetQuery(conection, input$query)
return(df)
})
The problem is that when the user types a wrong syntax in the textAreaInput the Shiny App closes and the error is shown in the R Console.
What I want is to print that error in the app so the user can try again and write another query.
Can someone help me please?
We can use tryCatch. Here is a complete example based on #Fan Li's answer here
library(RSQLite)
con <- dbConnect(SQLite(), dbname="sample.sqlite")
dbWriteTable(con, "test", data.frame(value1 = letters[1:4], value2 = letters[5:8]))
dbDisconnect(con)
library(shiny)
library(RSQLite)
runApp(list(
ui = bootstrapPage(
#select * from te fail
#select * from test work
textAreaInput("query",'Query'),
actionButton("action", label = "Run Query"),
hr(),
tableOutput("table")
),
server = function(input, output){
#Reactive is eager by definition and it will signal unreal/annoying errors, hence I used eventReactive
data <- eventReactive(input$action,{
tryCatch({
con <- dbConnect(SQLite(), dbname="sample.sqlite")
data<-dbGetQuery(con, input$query)
dbDisconnect(con)
return(data)
},
error = function(e){
showModal(
modalDialog(
title = "Error Occurred",
tags$i("Please enter valid query and try again"),br(),br(),
tags$b("Error:"),br(),
tags$code(e$message)
)
)
})
})
output$table <- renderTable(data())
}))

JSON Parse Error in MongoDB and R

I am new to R and MongoDB and everything related to programming so please bear with me. I am trying to query a MongoDB database based on user input (dropdown menu). When I run the code, I get the following error:
Error: com.mongodb.util.JSONParseException:
{'Name':input$prod}
^
Here is my UI:
mydb <- mongoDbConnect("mysearch")
shinyUI(fluidPage(
titlePanel("MYsearch"),
sidebarPanel(
selectInput("prod", label = "Choose my Product/Service",
choices = list("Engineering", "Operations",
"Detection"), selected = "Engineering")
),
mainPanel(tableOutput("table1"))
)
))
Here is my server:
my <- mongoDbConnect("mysearch")
shinyServer(function(input, output) {
output$table1 <- renderTable({
dbGetQuery(mydb, "usercollection", "{'Name':input$prod}")
})
}
)
Thanks so much for your help.
Try this...
queryParam <- paste('{\'Name\':', input$prod, '}');
shinyServer(function(input, output) {
output$table1 <- renderTable({
dbGetQuery(mydb, "usercollection", queryParam)
})
}
)
Instead of passing the value stored in input$prod, you are passing the string "input$prod" to the function.

Resources