I'm trying to build a Shiny application which will be connected to an unstable PostgreSQL Database with DBI. It works fine when the database is stable, but gives Whitelabel Error whenever the database is slow or down for a moment. How can I configure my application so that it will keep trying to connect a number of times before throwing error? A sample code is given below:
library(shiny)
library(DBI)
con <- dbConnect(
RPostgres::Postgres(),
host = "myip",
port = "myport",
dbname = "mydb",
user = "user",
password = "password"
)
ui <- fluidPage(
tableOutput("mytable")
)
server <- function(input, output, session){
output$mytable <- renderTable(
dbGetQuery(
con,
"select * from mytable;"
)
)
}
shinyApp(ui, server)
We can try purrr::insistently() with rate_backoff as suggested by #r2evans, to retry the query waiting longer between each time up to a maximum of 4 in this case.
library(shiny)
library(DBI)
library(purrr)
con <- dbConnect(
RPostgres::Postgres(),
host = "myip",
port = "myport",
dbname = "mydb",
user = "user",
password = "password"
)
my_rate <- rate_backoff(
pause_base = 1,
pause_cap = 60,
pause_min = 1,
max_times = 4,
jitter = FALSE
)
ui <- fluidPage(
tableOutput("mytable")
)
server <- function(input, output, session) {
output$mytable <- renderTable(
insistently(~
dbGetQuery(
con,
"select * from mytable;"
), rate = my_rate, quiet = FALSE)()
)
}
shinyApp(ui, server)
Related
In this shiny app, three SQLs are running at startup.
However, this puts a heavy load on startup.
Is it possible to run SQL when each tab is selected?
ui.R
shinyUI(
navbarPage(title = NULL,
tabPanel("home","hello"),
tabPanel("1",
tableOutput("table1")),
tabPanel("2",
tableOutput("table2")),
tabPanel("3",
tableOutput("table3")))
)
server.R
shinyServer(function(input, output) {
output$table1 <- renderTable({
sql <- "SELECT * FROM City WHERE ID = '1';"
query <- sqlInterpolate(pool, sql)
dbGetQuery(pool, query)
})
output$table2 <- renderTable({
sql <- "SELECT * FROM City WHERE ID = '2';"
query <- sqlInterpolate(pool, sql)
dbGetQuery(pool, query)
})
output$table3 <- renderTable({
sql <- "SELECT * FROM City WHERE ID = '3';"
query <- sqlInterpolate(pool, sql)
dbGetQuery(pool, query)
})
})
global.R
library(shiny)
library(DBI)
library(pool)
pool <- dbPool(
drv = RMySQL::MySQL(),
dbname = "shinydemo",
host = "shiny-demo.csa7qlmguqrf.us-east-1.rds.amazonaws.com",
username = "guest",
password = "guest"
)
You can try reactive as the code bellow:
shinyServer = function(input, output){
reactive({
if (req(input$navbar) == "table1")
# Run your sql1
if (req(input$navbar) == "table2")
# Run your sql2
if (req(input$navbar) == "table3")
# Run your sql3
})
Hope it helps.
Note: The following is not a 'reproducible' example since it relies on a DB back end, but hopefully has enough to provide workable solution ideas.
I want to refresh my data if the database table changes. I am using a reactivePoll() for this one, happily. However, I want the reactivePoll() to forcibly kick in when input date range (or whatever input) changes and not wait for the poll interval to expire. How can I do both?
Here is the general idea of the code I have, but need to be improved to achieve the above result.
getTableData <- function(session, startDate, endDate) {
tableData <- reactivePoll(
60000, session,
checkFunc = function() {
dbconn <- dbConnect(MySQL(), group = 'mysql')
query <- dbSendQuery(
dbconn,
paste0('SELECT MAX(CREATED_AT) as lastCreated FROM MYDBTABLE;')
)
lastFeedback <- dbFetch(query, -1)
dbClearResult(query)
dbDisconnect(dbconn)
lastFeedback$lastCreated
},
valueFunc = function() {
query <- paste0(
"SELECT * FROM MYDBTABLE ",
"WHERE MY_DATE BETWEEN '",
startDate, "' AND '", endDate, "';"
)
dbconn <- dbConnect(MySQL(), group = 'mysql')
query <- dbSendQuery(dbconn, query)
refreshedData <- dbFetch(query, -1)
dbClearResult(query)
dbDisconnect(dbconn)
refreshedData
}
)
return(tableData())
}
server <- function(session, input, output) {
output$mydata <- renderDataTable({
datatable(mydbdata(session, input$mydates[1], input$mydates[2]))
})
}
ui <- fluidPage(
dateRangeInput(
'mydates', 'Select Dates:', start = Sys.Date() - 90, end = Sys.Date()
),
dataTableOutput('mydata')
)
shinyApp(ui = ui, server = server)
Following up on my comment, here's a possible alternative. Note that output$test is updated whenever slider is changed or invalidateLater() is fired -
library(shiny)
ui <- fluidPage(align = "center",
sliderInput("s", "slider", 1, 10, 1, step = 1),
verbatimTextOutput("test")
)
server <- shinyServer(function(input, output, session) {
x <- reactiveValues(x = NULL)
observeEvent(input$s, {
x$x <- "updated via slider" # simulates date changes
})
observe({
invalidateLater(5000, session) # simulates reactivePoll
x$x <- "updated via Poll"
})
output$test <- renderPrint({
x$x
})
})
shinyApp(ui, server)
I have a Shiny Application that uses a MongoDB (using mongolite). The application loads and saves to the database with no issues but I am trying to find a way to edit the MongoDB through a datatable(using DT) where when the user edits or deletes a row that they can press an actionbutton to update the mongoDB. When I try to run it currently I am getting
"Warning: Error in : argument must be bson or json."
Is there a way for me to edit from DT, convert it to the JSON Mongo is expecting from the Shiny app? Below is the code.
library(shiny)
library(DT)
library(mongolite)
ui <- fluidPage(
# Application title
titlePanel("MongoTest"),
# Sidebar
sidebarLayout(
sidebarPanel(
actionButton("submit", "Submit"),
actionButton("load","Load"),
actionButton("update","update"),
actionButton("deleteRows", "Delete Rows")
),
#Main UI
mainPanel(
fluidPage(
fluidRow(h2("Interactive Table", align="center")),
tags$hr(),
fluidRow(
DT::dataTableOutput("Interactive_Table")
)
)
)
)
)
server = function(input, output, session){
#Function that loads the information from the mongoDB
loadData <- function() {
# Connect to the database
db = mongo(collection = "collectionhere",db ="SET", url = "mongodb://localhost:27017")
# Read all the entries
data <- db$find()
return(data)
}
READ_IN_DATA=loadData()
values <- reactiveValues(dfWorking = READ_IN_DATA)
#Function that saves data to DB
saveData <- function(data) {
# Connect to the database
db = mongo(collection = "collectionhere",db ="SET", url = "mongodb://localhost:27017")
data <- as.data.frame(t(data))
db$insert(data)
}
updateData = function(data){
# Connect to the database
db = mongo(collection = "collectionhere",db ="SET", url = "mongodb://localhost:27017")
data <- as.data.frame(t(data))
#subjects$update('{}', '{"$set":{"has_age": false}}', multiple = TRUE)
db$update(data)
}
#Loading In the Data
observeEvent(input$load, {
loadData()
})
#Update the DB based off changes to the table
observeEvent(input$update, {
updated_df=as.data.frame(values$dfWorking)
updateData(t(updated_df))
})
#Deleting Rows
observeEvent(input$deleteRows,{
if (!is.null(input$Interactive_Table_rows_selected)) {
values$dfWorking <- values$dfWorking[-as.numeric(input$Interactive_Table_rows_selected),]
}
})
#DT Table
output$Interactive_Table = renderDataTable({
datatable(values$dfWorking,editable=TRUE
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
I guess I really don't understand this process like I thought I did. I found the link below, and it seems pretty helpful, but after making only slight modifications, I can't get it to do what I want.
R Shiny SQL Server Query
I just want to launch a webpage and have a user enter a parameter, to be passed into a query.
library(RODBCext)
library(shiny)
ui <- shinyUI(
pageWithSidebar(
headerPanel("Hide Side Bar example"),
sidebarPanel(
textInput("CATEGORY", "Enter CATEGORY below"),
submitButton(text="Submit")
),
mainPanel(
tabsetPanel(
tabPanel("Data", tableOutput("tbTable"))
)
)
)
)
browser()
server <- function(input, output, session)
myData <- reactive({
req(input$Id)
#connect to database
dbhandle = odbcDriverConnect('driver={SQL Server};server=my_server;database=data_WH;trusted_connection=true')
browser()
#build query
#query = "SELECT * FROM [my_db].[dbo].[my_table] where [CATEGORY] = '1070'"
query = "SELECT * FROM [my_db].[dbo].[my_table] where [CATEGORY] = ?"
browser()
#store results
res <- sqlExecute(channel = dbhandle,
query = query,
data = list(input$Id),
fetch = TRUE,
stringsAsFactors = FALSE)
#close the connection
odbcClose(dbhandle)
#return results
res
})
output$tbTable <-
renderTable(
myData()
)
shinyApp(ui = ui, server = server)
The SQL string is fine. I entered browser, to try to debug the script, as described in the link below.
https://shiny.rstudio.com/articles/debugging.html
browser()
It didn't pause the code; it didn't help me debug the code. It didn't do anything at all.
Any thoughts anyone?
It looks like your server function is incorrectly defined.
A function defined of the form
fn <- function(arg1, arg2)
expression1
expression2
Is actually going to be evaluated as
fn <- function(arg1, arg2){
expression1
}
expression2
In your server function, because you didn't place your braces, the only expression in the function definition is creating the myData reactive. Your output$tbTable element is completely separate from your function, never gets called in the app, and so your reactive is never processed. You should try this:
library(RODBCext)
library(shiny)
ui <- shinyUI(
pageWithSidebar(
headerPanel("Hide Side Bar example"),
sidebarPanel(
textInput("CATEGORY", "Enter CATEGORY below"),
submitButton(text="Submit")
),
mainPanel(
tabsetPanel(
tabPanel("Data", tableOutput("tbTable"))
)
)
)
)
server <- function(input, output, session)
{ # NOTE THE BRACE HERE
myData <- reactive({
req(input$CATEGORY)
#connect to database
dbhandle = odbcDriverConnect('driver={SQL Server};server=my_server;database=data_WH;trusted_connection=true')
#build query
#query = "SELECT * FROM [my_db].[dbo].[my_table] where [CATEGORY] = '1070'"
query = "SELECT * FROM [my_db].[dbo].[my_table] where [CATEGORY] = ?"
#store results
res <- sqlExecute(channel = dbhandle,
query = query,
data = list(input$CATEGORY),
fetch = TRUE,
stringsAsFactors = FALSE)
#close the connection
odbcClose(dbhandle)
#return results
res
})
output$tbTable <-
renderTable(
myData()
)
} # AND NOTE THE CLOSING BRACE HERE
shinyApp(ui = ui, server = server)
I am trying to do this autocomplete using a list which would be populated dynamically from a database everytime the applications loads. Unfortunately the following approach isn't working.
rm(list = ls())
library(shinysky)
library(shiny)
library(RMySQL)
loadData <- function(publisherId) {
# Connect to the database
mydb = dbConnect(MySQL(), user='root', password='root',host='localhost',dbname="tq")
# Construct the fetching query
query <- sprintf("select * from tq.publisher_dim where publisher_id = %s",publisherId) # Submit the fetch query and disconnect
data <- dbGetQuery(mydb, query)
dbDisconnect(mydb)
data
}
loadPubIds <- function() {
# Connect to the database
mydb = dbConnect(MySQL(), user='root', password='root', host='localhost', dbname="tq")
# Construct the fetching query
query <- sprintf("select distinct publisher_id from tq.publisher_dim" )
# Submit the fetch query and disconnect
data <- dbGetQuery(mydb, query)
dbDisconnect(mydb)
data
}
my_autocomplete_list <- c(loadPubIds())
ui <- fluidPage(
select2Input("txt","",choices = NULL,selected = NULL),
textInput(inputId ="publisherId", label="choose publisherId", value = "", width = NULL, placeholder = NULL),
actionButton("goButton", "Go!"),
dataTableOutput('mytable')
#textOutput('myquery')
)
server <- function(input, output,session) {
test <- reactive({
pubs <- loadPubIds()
})
observe({
pubs <- loadPubIds()
updateSelect2Input(session, 'txt', choices = as.list(pubs), label = "")
})
output$mytable <- renderDataTable({
if (input$goButton == 0)
return()
isolate({ loadData(input$publisherId) })
})
}
shinyApp(ui = ui, server = server)
Any help would be great.