Persistent data storage in Shiny apps
Last Updated: 09 Mar 2017
By: Dean Attali
Shiny apps often need to save data, either to load it back into a different session or to simply log some information. However, common methods of storing data from R may not work well with Shiny. Functions like write.csv() and saveRDS() save data locally, but consider how shinyapps.io works.
shiny应用程序通常需要保存数据,或者将数据加载到另一个会话中,或者仅仅记录一些信息。然而,从R中用shiny存储数据的常用方法可能不太好用。诸如write.csv()和saveRDS()等函数在本地保存数据,但考虑一下shinyapps。io的作品
Shinyapps.io is a popular server for hosting Shiny apps. It is designed to distribute your Shiny app across different servers, which means that if a file is saved during one session on some server, then loading the app again later will probably direct you to a different server where the previously saved file doesn’t exist.
Shinyapps。Io(Shinyapp.io 是RStudio 为Shiny 进行网络部署而设计的)是一个很受欢迎的服务器,用来托管shiny的应用程序。它的目的是在不同的服务器上发布您的应用程序,这意味着如果在某个服务器上的一个会话中保存了一个文件,那么稍后再加载该应用程序可能会将您引导到另一个服务器,而以前保存的文件并不存在
在其他情况下,您可能会使用太大的数据以有效的方式在本地存储R。
On other occasions, you may use data that is too big to store locally with R in an efficient manner.
在其他情况下,您可能会使用太大的数据以有效的方式在本地存储R。
This guide will explain seven methods for storing persistent data remotely with a Shiny app. You will learn how to store:
本指南将解释七种方法,通过一个shiny应用程序,远程存储持久数据。
Arbitrary data can be stored as a file in some sort of a file system (local file system, Dropbox, Amazon S3)
Structured rectangular data can be stored as a table in a relational database or table-storage service (SQLite, MySQL, Google Sheets)
Semi-structured data can be stored as a collection in a NoSQL database (MongoDB)
任意数据可以存储为文件系统中的文件(本地文件系统,Dropbox,Amazon S3)结构化的矩形数据可以存储在关系数据库或表存储服务中(SQLite,MySQL,谷歌表)半结构化数据可以存储在NoSQL数据库中(MongoDB)
The article explains the theory behind each method, and augments the theory with working examples that will make it clear and easy for you to use these methods in your own apps.
这篇文章解释了每种方法背后的理论,并通过实例来增强理论,使你在自己的应用程序中使用这些方法变得更加清晰和容易。
As a complement to this article, you can see a live demo of a Shiny app that uses each of the seven storage methods to save and load data (source code on GitHub). This article expands on Jeff Allen’s article regarding sharing data across sessions.
Table of contents
作为本文的补充,您可以看到一个使用七个存储方法来保存和加载数据的shiny应用程序的现场演示(GitHub上的源代码)。本文扩展了Jeff Allen关于跨会话共享数据的文章。
Basic Shiny app without data storage无数据存储的基础shiny应用
Local vs remote storage本地和远程存储
Persistent data storage methods持久数据存储方法
Store arbitrary data in a file将任意数据存储在文件中
Local file system (local)本地文件系统
Dropbox (remote)远程
Amazon S3 (remote)远程
Store structured data in a table将结构化数据存储在表中
SQLite (local)本地
MySQL (local or remote)本地或远程
Google Sheets (remote)远程
Store semi-structured data in a NoSQL database在NoSQL数据库中存储半结构化数据
MongoDB (local or remote)本地或远程
Conclusion
Basic Shiny app without data storage无数据储存的shiny app 基础应用
To demonstrate how to store data using each storage type, we’ll start with a simple form-submission Shiny app that
collects some information from the user
stores their response, and
shows all previous responses
为了演示如何使用每个存储类型存储数据,我们将从一个简单的表单提交闪亮应用开始
1.从用户那里收集一些信息
2.商店和他们的反应
3.显示所有以前的响应
Initially the app will only save responses within its R session. We will learn later how to modify the app to use each different storage type.最初,这个应用只会在它的R会话中保存响应。稍后我们将学习如何修改应用程序以使用不同的存储类型
Here is the code for the basic app that we will be using as our starting point—copy it into a file named app.R. (In case you didn’t know: Shiny apps don’t have to be broken up into separate ui.R and server.R files, they can be completely defined in one file as this Shiny article explains)下面是我们将使用的基本应用程序的代码,我们将把它作为我们的起点复制到一个名为app.R的文件中。(以防你不知道:闪亮的应用程序不需要被拆分为单独的ui。R和服务器。R文件,它们可以在一个文件中完全定义,正如这篇闪亮的文章解释的那样
library(shiny)
# Define the fields we want to save from the form
fields <- c("name", "used_shiny", "r_num_years")定义要从表单中保存的字段
# Shiny app with 3 fields that the user can submit data for有三个字段的闪亮应用,用户可以提交数据
shinyApp(
ui = fluidPage(
DT::dataTableOutput("responses", width = 300), tags$hr(),
textInput("name", "Name", ""),
checkboxInput("used_shiny", "I‘ve built a Shiny app in R before", FALSE),
sliderInput("r_num_years", "Number of years using R",
0, 25, 2, ticks = FALSE),
actionButton("submit", "Submit")
),
server = function(input, output, session) {
# Whenever a field is filled, aggregate all form data每当填充字段时,聚合所有表单数据
formData <- reactive({
data <- sapply(fields, function(x) input[[x]])
data
})
# When the Submit button is clicked, save the form data当单击Submit按钮时,保存表单数据
observeEvent(input$submit, {
saveData(formData())
})
# Show the previous responses显示以前的响应
# (update with current response when Submit is clicked)(单击Submit后更新当前响应)
output$responses <- DT::renderDataTable({
input$submit
loadData()
})
}
)
The above code is taken from a guide on how to mimic a Google form with Shiny.
The above app is very simple—there is a table that shows all responses, three input fields, and a Submit button that will take the data in the input fields and save it. You might notice that there are two functions that are not defined but are used in the app: saveData(data) and loadData(). These two functions are the only code that affects how the data is stored/retrieved, and we will redefine them for each data storage type. In order to make the app work for now, here’s a trivial implementation of the save and load functions that simply stores responses in the current R session.
上面的代码取自一个如何模拟谷歌表单和发光的指南
上面的应用程序非常简单——有一个表显示所有的响应、三个输入字段和一个提交按钮,它将接收输入字段中的数据并保存它。您可能会注意到,有两个函数没有定义,但是在应用程序中使用:saveData(数据)和loadData()。这两个函数是唯一影响数据存储/检索方式的代码,我们将为每个数据存储类型重新定义它们。为了让应用程序现在工作,这里有一个简单的保存和加载函数的实现,它只是存储在当前的R会话中的响应
saveData <- function(data) {
data <- as.data.frame(t(data))
if (exists("responses")) {
responses <<- rbind(responses, data)
} else {
responses <<- data
}
}
loadData <- function() {
if (exists("responses")) {
responses
}
}
Before continuing further, make sure this basic app works for you and that you understand every line in it—it is not difficult, but take the two minutes to go through it. The code for this app is also available as a gist and you can run it either by copying all the code to your RStudio IDE or by running shiny::runGist("c4db11d81f3c46a7c4a5").
Local vs remote storage
在继续之前,确保这个基本的应用程序适合你,并且你理解每一行——这并不难,但要花两分钟去完成它。这个应用程序的代码也可以作为一个要点,你可以通过将所有代码复制到RStudio IDE或运行闪亮的::runGist(“c4db11d81f3c46a7c4a5”)来运行它
本地和远程储存
Before diving into the different storage methods, one important distinction to understand is local storage vs remote storage.在深入研究不同存储方法之前,要理解的一个重要区别是本地存储与远程存储。
Local storage means saving a file on the same machine that is running the Shiny application. Functions like write.csv(), write.table(), and saveRDS() implement local storage because they will save a file on the machine running the app. Local storage is generally faster than remote storage, but it should only be used if you always have access to the machine that saves the files.
本地存储意味着在运行闪亮应用程序的同一台机器上保存文件。像write.csv()、write.table()和saveRDS()这样的函数实现本地存储,因为它们可以在运行应用程序的机器上保存文件。本地存储通常比远程存储快,但如果你总是能够访问保存文件的机器,则只能使用它。
Remote storage means saving data on another server, usually a reliable hosted server such as Dropbox, Amazon, or a hosted database. One big advantage of using hosted remote storage solutions is that they are much more reliable and can generally be more trusted to keep your data alive and not corrupted.
远程存储意味着在另一台服务器上保存数据,通常是可靠的托管服务器,如Dropbox、Amazon或托管数据库。使用托管远程存储解决方案的一个很大的优点是,它们更可靠,通常可以更可信地保存数据,而不会损坏数据。
When going through the different storage type options below, keep in mind that if your Shiny app is hosted on shinyapps.io, you will have to use a remote storage method for the time being. RStudio plans to implement persistent storage on shinyapps.io soon. In the meantime, using local storage is only an option if you’re hosting your own Shiny Server, though that comes at the price of having to manage a server and should only be done if you’re comfortable with administering a server.
在浏览不同的存储类型选项时,请记住,如果你的闪亮应用程序是在shinyapps上运行的。io,你将不得不暂时使用远程存储方法。RStudio计划在shinyapps上实现持久存储。io。与此同时,如果您拥有自己的闪亮服务器,那么使用本地存储只是一种选择,尽管这是要管理服务器的代价,而且如果您对管理服务器感到满意,那么就应该这样做。
Persistent data storage methods持久数据储存方法
Using the above Shiny app, we can store and retrieve responses in many different ways. Here we will go through seven ways to achieve data persistence that can be easily integrated into Shiny apps. For each method, we will explain the method and provide a version of saveData() and loadData() that implements the method. To use a method as the storage type in the example app, run the app with the appropriate version of saveData() and loadData().
使用上面的闪亮应用,我们可以以不同的方式存储和检索响应。在这里,我们将通过七种方法来实现数据持久性,这些数据持久性可以很容易地集成到闪亮的应用程序中。对于每种方法,我们将解释方法并提供实现方法的saveData()和loadData()的版本。要使用示例应用程序中存储类型的方法,使用saveData()和loadData()的适当版本运行应用程序。
As a reminder, you can see all the seven different storage types being used, along with the exact code used, in this live Shiny app.
作为一个提醒,您可以看到使用的所有七种不同的存储类型,以及使用的精确代码,在这个具有光泽的应用程序中。
Here is a summary of the different storage types we will learn to use.下面是我们将学习使用的不同存储类型的摘要。
Method 方法 |
Data type 数据类型 |
Local storage本地存储 |
Remote storage远程存储 |
R package |
Local file system |
Arbitrary data 任意数据 |
YES |
- |
|
Dropbox |
Arbitrary data |
YES |
rdrop2 |
|
Amazon S3 |
Arbitrary data |
YES |
aws.s3 |
|
SQLite |
Structured data结构化数据 |
YES |
RSQLite |
|
MySQL |
Structured data |
YES |
YES |
RMySQL |
Google Sheets |
Structured data |
YES |
googlesheets |
|
MongoDB |
Semi-structured data |
YES |
YES |
mongolite |
Store arbitrary data in a file将任意数据存储在文件中
This is the most flexible option to store data since files allow you to store any type of data, whether it is a single value, a big data.frame, or any arbitrary data. There are two common cases for using files to store data:
这是存储数据最灵活的选项,因为文件允许您存储任何类型的数据,无论是单个值还是大数据。框架,或任意数据。使用文件存储数据有两个常见的情况:
you have one file that gets repeatedly overwritten and used by all sessions (like the example in Jeff Allen’s article), or
you save a new file every time there is new data1.
您有一个文件,它多次被覆盖并被所有会话使用(比如Jeff Allen的文章中的例子),或者
2.每次有新数据时,您都保存一个新文件
In our case we’ll use the latter because we want to save each response as its own file. We can use the former option, but then we would introduce the potential for race conditions which will overcomplicate the app. A race condition happens when two users submit a response at the exact same time, but since the file cannot deal with multiple edits simultaneously, one user will overwrite the response of the other user.
在我们的例子中,我们将使用后者,因为我们希望将每个响应保存为自己的文件。我们可以使用前的选择,然后我们会介绍潜在的竞态条件将使应用程序复杂化。竞态条件当两个用户提交一个反应在同一时间,但由于文件不能同时处理多个编辑,一个用户将覆盖其他用户的反应。
When saving multiple files, it is important to save each file with a different file name to avoid overwriting files. There are many ways to do this. For example, you can simply use the current timestamp and an md5 hash of the data being saved as the file name to ensure that no two form submissions have the same file name.在保存多个文件时,重要的是要用不同的文件名保存每个文件,以避免过度写入文件。有很多方法可以做到这一点。例如,您可以简单地使用当前时间戳和将数据保存为文件名的md5散列,以确保没有两个表单提交具有相同的文件名
Arbitrary data can be stored in a file either on the local file system or on remote services such as Dropbox or Amazon S3.任意数据可以存储在本地文件系统的文件中,也可以存储在诸如Dropbox或Amazon S3这样的远程服务上
1. Local file system (local)本地文件系统
The most trivial way to save data from Shiny is to simply save each response as its own file on the current server. To load the data, we simply load all the files in the output directory. In our specific example, we also want to concatenate all of the data files together into one data.frame.最简单的方法就是将每个响应保存为当前服务器上自己的文件。要加载数据,只需将所有文件加载到输出目录中。在我们的具体示例中,我们还希望将所有的数据文件连接到一个data . frame中。
Setup: The only setup required is to create an output directory (responses in this case) and to ensure that the Shiny app has file permissions to read/write in that directory.
设置:唯一需要的设置是创建一个输出目录(在本例中是响应),并确保闪亮的应用程序拥有在该目录中读取/写入的文件权限。
Code:代码
outputDir <- "responses"
saveData <- function(data) {
data <- t(data)
# Create a unique file name创建一个惟一的文件名
fileName <- sprintf("%s_%s.csv", as.integer(Sys.time()), digest::digest(data))
# Write the file to the local system将该文件写入本地系统
write.csv(
x = data,
file = file.path(outputDir, fileName),
row.names = FALSE, quote = TRUE
)
}
loadData <- function() {
# Read all the files into a list将所有文件读入一个列表
files <- list.files(outputDir, full.names = TRUE)
data <- lapply(files, read.csv, stringsAsFactors = FALSE)
# Concatenate all data together into one data.frame将所有数据连接到一个数据框中
data <- do.call(rbind, data)
data
}
2. Dropbox (remote)远程
If you want to store arbitrary files with a remote hosted solution instead of the local file system, you can store files on Dropbox. Dropbox is a file storing service which allows you to host any file, up to a certain maximum usage. The free account provides plenty of storage space and should be enough to store most data from Shiny apps.
如果您希望使用远程托管解决方案存储任意文件,而不是本地文件系统,则可以存储Dropbox上的文件。Dropbox是一种文件存储服务,它允许你托管任何文件,达到一定的最大使用率。这个免费帐户提供了大量的存储空间,应该足够存储来自闪亮应用的大部分数据。
This approach is similar to the previous approach that used the local file system. The only difference is that now that files are being saved to and loaded from Dropbox. You can use the rdrop2 package to interact with Dropbox from R. Note that rdrop2 can only move existing files onto Dropbox, so we still need to create a local file before storing it on Dropbox.
这种方法类似于以前使用本地文件系统的方法。唯一不同的是,现在文件被保存在Dropbox上。你可以使用rdrop2软件包与Dropbox的Dropbox进行互动,rdrop2只能将现有的文件移动到Dropbox上,所以我们仍然需要在Dropbox上存储之前创建一个本地文件
Setup: You need to have a Dropbox account and create a folder to store the responses. You will also need to add authentication to rdrop2 with any approach suggested in the package README. The authentication approach I chose was to authenticate manually once and to copy the resulting .httr-oauth file that gets created into the Shiny app’s folder.
设置:您需要有一个Dropbox帐户,并创建一个文件夹来存储响应。您还需要向rdrop2添加身份验证,并在包README中提出任何方法。我选择的身份验证方法是手动验证一次并复制结果。httr - oauth文件被创建到闪亮的应用程序的文件夹中。
Code:代码
library(rdrop2)
outputDir <- "responses"
saveData <- function(data) {
data <- t(data)
# Create a unique file name创建一个惟一的文件名
fileName <- sprintf("%s_%s.csv", as.integer(Sys.time()), digest::digest(data))
# Write the data to a temporary file locally将数据发送到本地的临时文件
filePath <- file.path(tempdir(), fileName)
write.csv(data, filePath, row.names = FALSE, quote = TRUE)
# Upload the file to Dropbox上传文件到Dropbox
drop_upload(filePath, dest = outputDir)
}
loadData <- function() {
# Read all the files into a list将所有文件读入一个列表
filesInfo <- drop_dir(outputDir)
filePaths <- filesInfo$path
data <- lapply(filePaths, drop_read_csv, stringsAsFactors = FALSE)
# Concatenate all data together into one data.frame将所有数据连接到一个数据框中
data <- do.call(rbind, data)
data
}
3. Amazon S3 (remote)远程
Another popular alternative to Dropbox for hosting files online is Amazon S3, or S3 in short. Just like with Dropbox, you can host any type of file on S3, but instead of placing files inside directories, in S3 you place files inside of buckets. You can use the aws.s3 package to interact with S3 from R. Note that the package is not yet on CRAN so you will have to look at its README for installation instructions.
Dropbox在线托管文件的另一个流行选择是Amazon S3,简称S3。就像Dropbox一样,你可以在S3上托管任何类型的文件,而不是把文件放在目录中,在S3中,你把文件放在桶里。你可以用aws。s3包与s3交互,从r注意到包尚未在CRAN上,所以您必须查看它的README安装说明。
Setup: You need to have an Amazon Web Services account and to create an S3 bucket to store the responses. As the package documentation explains, you will need to set a few environment variables in order to call the API.
设置:您需要一个Amazon Web服务帐户,并创建一个S3存储桶来存储响应。正如包文档解释的那样,您需要设置一些环境变量以调用API。
Code:代码
library(aws.s3)
s3BucketName <- "my-unique-s3-bucket-name"
Sys.setenv("AWS_ACCESS_KEY_ID" = "key",
"AWS_SECRET_ACCESS_KEY" = "secret",
"AWS_DEFAULT_REGION" = "region")
saveData <- function(data) {
# Create a temporary file to hold the data创建一个临时文件来保存数据
data <- t(data)
file_name <- paste0(
paste(
get_time_human(),
digest(data, algo = "md5"),
sep = "_"
),
".csv"
)
file_path <- file.path(tempdir(), file_name)
write.csv(data ,file_path, row.names = FALSE, quote = TRUE)
# Upload the file to S3 将文件上载到S3
put_object(file = file_path, object = file_name, bucket = s3BucketName)
}
loadData <- function() {
# Get a list of all files获取所有文件的列表
file_names <- get_bucket_df(s3BucketName)[["Key"]]
# Read all files into a list将所有文件读入一个列表
data <- lapply(file_names, function(x) {
object <- get_object(x, s3BucketName)
object_data <- readBin(object, "character")
read.csv(text = object_data, stringsAsFactors = FALSE)
})
# Concatenate all data together into one data.frame将所有数据连接到一个数据框中
data <- do.call(rbind, data)
data
}
Store structured data in a table将结构化数据存储在表中
If the data you want to save is structured and rectangular, storing it in a table would be a good option. Loosely defined, structured data means that each observation has the same fixed fields, and rectangular data means that all observations contain the same number of fields and fit into a nice 2D matrix. A data.frame is a great example of such data, and thus data.frames are ideal candidates to be stored in tables such as relational databases.
如果您想要保存的数据是结构化和矩形的,那么将其存储在一个表中是一个不错的选择。松散定义的结构化数据意味着每一个观察都有相同的固定字段,而矩形数据意味着所有的观测都包含相同数量的字段,并符合一个漂亮的2D矩阵。一个数据。框架是此类数据的一个很好的例子,因此是数据。框架是存储在关系数据库等表中的理想候选对象。
Structured data must have some schema that defines what the data fields are. In a data.frame, the number and names of the columns can be thought of as the schema. In tables with a header row, the header row can be thought of as the schema.
结构化数据必须有某种模式来定义数据字段。在一个数据。框架、数字和列的名称可以被认为是模式。在有标题行的表中,标题行可以被认为是模式。
Structured data can be stored in a table either in a relational database (such as SQLite or MySQL) or in any other table-hosting service such as Google Sheets. If you have experience with database interfaces in other languages, you should note that R does not currently have support for prepared statements, so any SQL statements have to be constructed manually. One advantage of using a relational database is that with most databases it is safe to have multiple users using the database concurrently without running into race conditions thanks to transaction support.
结构化数据可以存储在关系数据库(如SQLite或MySQL)中,也可以存储在诸如谷歌表之类的其他桌面托管服务中。如果您有其他语言的数据库接口的经验,您应该注意到,R目前还不支持准备好的语句,因此必须手动构造任何SQL语句。使用关系数据库的一个优点是,在大多数数据库中,由于事务支持,可以同时使用数据库同时使用数据库,而不需要运行到竞争环境。
4.SQLite(本地)
SQLite is a very simple and light-weight relational database that is very easy to set up. SQLite is serverless, which means it stores the database locally on the same machine that is running the shiny app. You can use the RSQLite package to interact with SQLite from R. To connect to a SQLite database in R, the only information you need to provide is the location of the database file.
SQLite是一个非常简单和轻量级的关系数据库,很容易设置。SQLite是serverless,这意味着它在本地存储数据库在同一台机器上运行的应用程序,您可以使用RSQLite包与SQLite从R R .连接到SQLite数据库,您需要提供的唯一信息是数据库文件的位置。
To store data in a SQLite database, we loop over all the values we want to add and use a SQL INSERT statement to add the data to the database. It is essential that the schema of the database matches exactly the names of the columns in the Shiny data, otherwise the SQL statement will fail. To load all previous data, we use a plain SQL SELECT * statement to get all the data from the database table.
为了将数据存储在SQLite数据库中,我们遍历所有想要添加的值,并使用SQL INSERT语句将数据添加到数据库中。至关重要的是,数据库的模式恰好匹配闪亮数据中的列的名称,否则SQL语句将失败。为了加载所有以前的数据,我们使用一个简单的SQL SELECT *语句从数据库表中获取所有数据。
Setup: First, you must have SQLite installed on your server. Installation is fairly easy; for example, on an Ubuntu machine you can install SQLite with sudo apt-get install sqlite3 libsqlite3-dev. If you use shinyapps.io, SQLite is already installed on the shinyapps.io server, which will be a handy feature in future versions of shinyapps.io, which will include persistent local storage.
设置:首先,您必须在服务器上安装SQLite。安装很简单;例如,在Ubuntu的机器上,您可以安装SQLite和sudo apt - get安装sqlite3 libsqlite3 - dev。如果你使用shinyapps。io,SQLite已经安装在shinyapps上了。io服务器,这将是未来版本的shinyapps的一个方便的功能。io,它将包括持久的本地存储。
You also need to create a database and a table that will store all the responses. When creating the table, you need to set up the schema of the table to match the columns of your data. For example, if you want to save data with columns “name” and “email” then you can create the SQL table with CREATE TABLE responses(name TEXT, email TEXT);. Make sure the shiny app has write permissions on the database file and its parent directory.
您还需要创建一个数据库和一个存储所有响应的表。在创建表时,需要设置表的模式来匹配数据的列。例如,如果您想要保存具有列“名称”和“电子邮件”的数据,那么您可以创建带有创建表响应的SQL表(名称文本、电子邮件文本);确保shiny的应用程序具有数据库文件及其父目录的写权限。
Code:代码
library(RSQLite)
sqlitePath <- "/path/to/sqlite/database"
table <- "responses"
saveData <- function(data) {
# Connect to the database连接到数据库
db <- dbConnect(SQLite(), sqlitePath)
# Construct the update query by looping over the data fields通过循环遍历数据字段来构造更新查询
query <- sprintf(
"INSERT INTO %s (%s) VALUES (‘%s‘)",
table,
paste(names(data), collapse = ", "),
paste(data, collapse = "‘, ‘")
)
# Submit the update query and disconnect提交更新查询和断开连接
dbGetQuery(db, query)
dbDisconnect(db)
}
loadData <- function() {
# Connect to the database连接到数据库
db <- dbConnect(SQLite(), sqlitePath)
# Construct the fetching query构建获取查询
query <- sprintf("SELECT * FROM %s", table)
# Submit the fetch query and disconnect提交fetch查询并断开连接
data <- dbGetQuery(db, query)
dbDisconnect(db)
data
}
5. MySQL (local or remote)本地或远程
MySQL is a very popular relational database that is similar to SQLite but is more powerful. MySQL databases can either be hosted locally (on the same machine as the Shiny app) or online using a hosting service.
MySQL是一个非常受欢迎的关系数据库,与SQLite类似,但功能更强大。MySQL数据库可以本地托管(在同一台机器上使用闪亮的应用程序),也可以使用托管服务在线托管。
This method is very similar to the previous SQLite method, with the main difference being where the database is hosted. You can use the RMySQL package to interact with MySQL from R. Since MySQL databases can be hosted on remote servers, the command to connect to the server involves more parameters, but the rest of the saving/loading code is identical to the SQLite approach. To connect to a MySQL database, you need to provide the following parameters: host, port, dbname, user, password.
这种方法与以前的SQLite方法非常相似,主要区别在于数据库托管的地方。由于MySQL数据库可以在远程服务器上托管,因此可以使用RMySQL包与MySQL进行交互,而连接到服务器的命令包含更多的参数,但是其余的保存/加载代码与SQLite方法完全相同。要连接到MySQL数据库,需要提供以下参数:主机、端口、dbname、用户和密码。
Setup: You need to create a MySQL database (either locally or using a web service that hosts MySQL databases) and a table that will store the responses. As with the setup for SQLite, you need to make sure the table schema is properly set up for your intended data.
设置:您需要创建一个MySQL数据库(本地或使用MySQL数据库的web服务)和一个存储响应的表。与SQLite的设置一样,您需要确保为您的预期数据正确设置表模式。
代码:
library(RMySQL)
options(mysql=
list(
"host"
=
"127.0.0.1",
"port"
=
3306,
"user"
=
"myuser",
"password"
=
"mypassword"
))
databaseName<-
"myshinydatabase"
table<-
"responses"
saveData<-
function(data)
{
# Connect to the database连接到数据库
db
<-
dbConnect(MySQL(),
dbname
=
databaseName,
host
=
options()$mysql$host,
port
=
options()$mysql$port,
user
=
options()$mysql$user,
password
=
options()$mysql$password)
# Construct the update query by looping over the data fields通过循环遍历数据字段来构造更新查询
query
<-
sprintf(
"INSERT INTO %s (%s) VALUES (‘%s‘)",
table,
paste(names(data),
collapse
=
", "),
paste(data,
collapse
=
"‘, ‘")
)
# Submit the update query and disconnect提交更新查询和断开连接
dbGetQuery(db,
query)
dbDisconnect(db)
}
loadData<-
function()
{
# Connect to the database连接到数据库
db
<-
dbConnect(MySQL(),
dbname
=
databaseName,
host
=
options()$mysql$host,
port
=
options()$mysql$port,
user
=
options()$mysql$user,
password
=
options()$mysql$password)
# Construct the fetching query 构建获取查询
query
<-
sprintf("SELECT * FROM %s",
table)
# Submit the fetch query and disconnect提交fetch查询并断开连接
data
<-
dbGetQuery(db,
query)
dbDisconnect(db)
data
}
6.谷歌表(远程)
If you don’t want to deal with the formality and rigidity of a database, another option for storing tabular data is in a Google Sheet. One nice advantage of Google Sheets is that they are easy to access from anywhere; but unlike with databases, with Google Sheets data can be overwritten with multiple concurrent users.
如果您不想处理数据库的形式和刚度,那么存储表格数据的另一个选项是在谷歌表中。谷歌被单的一个优点是它们易于从任何地方访问;但与数据库不同的是,使用谷歌表数据可以覆盖多个并发用户。
You can use the googlesheets package to interact with Google Sheets from R. To connect to a specific sheet, you will need either the sheet’s title or key (preferably key, as it is unique). It is very easy to store or retrieve data from a Google Sheet, as the code below shows.
您可以使用googlesheets包与来自r的谷歌表进行交互,以连接到特定的表单,您将需要该表单的标题或密钥(最好是密钥,因为它是唯一的)。可以很容易地从谷歌表中存储或检索数据,如下面的代码所示。
Setup: All you need to do is create a Google Sheet and set the top row with the names of the fields. You can do that either via a web browser or by using the googlesheets package. You also need to have a Google account. The googlesheets package uses a similar approach to authentication as rdrop2, and thus you also need to authenticate in a similar fashion, such as by copying a valid .httr-oauth file to your Shiny directory.
设置:您所需要做的就是创建一个谷歌表,并在上面一行中设置字段的名称。您可以通过web浏览器或使用googlesheets包来实现这一点。您还需要一个谷歌帐户。googlesheets包使用类似于rdrop2的认证方法,因此您也需要以类似的方式进行身份验证,比如复制一个有效的。httr - oauth文件到您的shiny目录。
代码:
library(googlesheets)
table<-
"responses"
saveData<-
function(data)
{
# Grab the Google Sheet拿谷歌表
sheet
<-
gs_title(table)
# Add the data as a new row将数据添加为新行
gs_add_row(sheet,
input
=
data)
}
loadData<-
function()
{
# Grab the Google Sheet 拿谷歌表
sheet
<-
gs_title(table)
# Read the data 读数据
gs_read_csv(sheet)
}
在NoSQL数据库中存储半结构化数据
If you have data that is not fully structured but is also not completely free-form, a good middle ground can be using a NoSQL database. NoSQL databases can also be referred to as schemaless databases because they do not use a formal schema. NoSQL databases still offer some of the benefits of a traditional relational database, but are more flexible because every entry can use different fields. If your Shiny app needs to store data that has several fields but there is no unifying schema for all of the data to use, then using a NoSQL database can be a good option.
如果您的数据没有完全结构化,但也不是完全自由的,那么一个好的中间体可以使用NoSQL数据库。NoSQL数据库也可以称为无模式数据库,因为它们不使用正式的模式。NoSQL数据库仍然提供了传统关系数据库的一些好处,但是更加灵活,因为每个条目都可以使用不同的字段。如果您的应用程序需要存储有多个字段的数据,但是对于所有使用的数据并没有统一的模式,那么使用NoSQL数据库是一个不错的选择。
There are many NoSQL databases available, but here we will only show how to use mongoDB.
这里有很多NoSQL数据库,但这里我们只展示如何使用mongoDB。
7.MongoDB(本地或远程)
MongoDB is one of the most popular NoSQL databases, and just like MySQL it can be hosted either locally or remotely. There are many web services that offer mongoDB hosting, including MongoLab which gives you free mongoDB databases. In mongoDB, entries (in our case, responses) are stored in a collection (the equivalent of an S3 bucket or a SQL table).
MongoDB是最受欢迎的NoSQL数据库之一,和MySQL一样,它可以在本地或远程托管。有许多提供mongoDB托管的web服务,包括MongoLab,它提供了免费的mongoDB数据库。在mongoDB中,条目(在我们的示例中,响应)存储在一个集合中(相当于S3 bucket或SQL表)。
You can use the mongolite package to interact with mongoDB from R. As with the relational database methods, all we need to do in order to save/load data is connect to the database and submit the equivalent of an update or select query. To connect to the database you need to provide the following: db, host, username, password. When saving the data, mongolite requires the data to be in a data.frame format.
您可以使用mongolite包与mongoDB进行交互,就像使用关系数据库方法一样,为了保存/加载数据,我们所需要做的就是连接到数据库,并提交相当于update或select查询的数据。要连接到数据库,您需要提供以下内容:db、主机、用户名、密码。在保存数据时,mongolite需要数据的数据。帧格式。
Setup: All you need to do is create a mongoDB database—either locally or using a web service such as MongoLab. Since there is no schema, it is not mandatory to create a collection before populating it.
设置:您所需要做的就是在本地创建mongoDB数据库,或者使用像MongoLab这样的web服务。由于没有模式,所以在填充集合之前不强制创建集合。
代码:
library(mongolite)
options(mongodb=
list(
"host"
=
"ds012345.mongolab.com:61631",
"username"
=
"myuser",
"password"
=
"mypassword"
))
databaseName<-
"myshinydatabase"
collectionName<-
"responses"
saveData<-
function(data)
{
# Connect to the database连接到数据库
db
<-
mongo(collection
=
collectionName,
url
=
sprintf(
"mongodb://%s:%[email protected]%s/%s",
options()$mongodb$username,
options()$mongodb$password,
options()$mongodb$host,
databaseName))
# Insert the data into the mongo collection as a data.frame将数据插入mongo集合作为数据
data
<-
as.data.frame(t(data))
db$insert(data)
}
loadData<-
function()
{
# Connect to the database 连接到数据库
db
<-
mongo(collection
=
collectionName,
url
=
sprintf(
"mongodb://%s:%[email protected]%s/%s",
options()$mongodb$username,
options()$mongodb$password,
options()$mongodb$host,
databaseName))
# Read all the entries阅读所有的条目
data
<-
db$find()
data
}
结论
Persistent storage lets you do more with your Shiny apps. You can even use persistent storage to access and write to remote data sets that would otherwise be too big to manipulate in R.
持久存储可以让你用你的闪亮应用做更多事情。您甚至可以使用持久性存储来访问和写入远程数据集,否则这些数据集太大,无法在R中操作。
The following table can serve as a reminder of the different storage types and when to use them. Remember that any method that uses local storage can only be used on Shiny Server, while any method that uses remote storage can be also used on shinyapps.io.
下表可以提醒您不同的存储类型以及何时使用它们。请记住,任何使用本地存储的方法只能在闪亮的服务器上使用,而使用远程存储的任何方法也可以在shinyapps.io上使用。
Method |
Data type |
Local storage |
Remote storage |
R package |
Local file system |
Arbitrary data |
YES |
- |
|
Dropbox |
Arbitrary data |
YES |
rdrop2 |
|
Amazon S3 |
Arbitrary data |
YES |
aws.s3 |
|
SQLite |
Structured data |
YES |
RSQLite |
|
MySQL |
Structured data |
YES |
YES |
RMySQL |
Google Sheets |
Structured data |
YES |
googlesheets |
|
MongoDB |
Semi-structured data |
YES |
YES |
mongolite |
You can view the original post of this article, and leave further comments, at http://deanattali.com/blog/shiny-persistent-data-storage/.
您可以查看本文的原文,然后离开进一步评论,http://deanattali.com/blog/shiny-persistent-data-storage/。
We love it when R users help each other, but RStudio does not monitor or answer the comments in this thread. If you‘d like to get specific help, we recommend the Shiny Discussion Forum for in depth discussion of Shiny related questions and How to get help for a list of the best ways to get help with R code.
comments powered by Disqus
当R用户互相帮助时,我们喜欢它,但是RStudio不监视或回答这个线程中的注释。如果你想要得到具体的帮助,我们推荐一个闪亮的讨论论坛,深入讨论闪亮的相关问题,以及如何获得帮助获得R代码的最佳方式的列表。
评论由Disqus