O MongoDB é um banco de dados NoSQL focado em alta performance e amplamente utilizado em aplicações web e cenários envolvendo big data. O software é livre e gratuito, podendo ser obtido diretamente em https://www.mongodb.com/.
Ao fim deste laboratório, você deverá ser capaz de:
O pacote essencial para esta atividade é o mongolite
. Ele deve estar instalado antes de você iniciar a atividade. Confirme, após a instalação, que ele funcionamento apropriadamente (dica: tente carregar o pacote). Se você estiver utilizando MS Windows para esta atividade, você pode se beneficiar do script apresentado abaixo. Se o sistema perguntar sobre instalar novos pacotes a partir do código-fonte (install newer version from source), responda n
(para indicar não
).
options(install.packages.check.source = "no")
install.packages('mongolite', type='win.binary', dependencies = TRUE)
Para este laboratório, serão utilizadas algumas observações do conjunto de dados diamonds
disponibilizado via ggplot2
. Adicionalmente, este laboratório assume que você já criou um usuário e senha na plataforma MongoDB Atlas (resultado do apontamento via mlab.com).
Conecte-se à plataforma MongoDB Atlas (https://www.mongodb.com/) usando as credenciais escolhidas por você na criação da conta (este login/senha costuma ser diferente do usuário/senha do banco de dados).
No menu à esquerda, escolha a opção Network Access, sob Security, clique em + ADD IP ADDRESS.
Ainda no menu à esquerda, escolha a opção Clusters (em ATLAS). Clique em Connect e escolha Connect Your Application. Copie a expressão em Connection String Only. Observe que a expressão inicia-se com mongodb+srv://
, que indica o protocolo de conexão. Em seguida, há o nome do usuário (no exemplo abaixo, benilton
), seguido do símbolo :
e da senha (em texto puro, aqui representada como <password>
). Após a senha, o símbolo @
indica que a informação seguinte indicará o nome do servidor a ser utilizado (cluster0-s8gg0.mongodb.net
). Após o nome do servidor a informação remanescente deverá ser removida (pois trata-se de um código de exemplo).
Desta maneira, a informação originalmente disponível:
mongodb+srv://benilton:<password>@cluster0-s8gg0.mongodb.net/test?retryWrites=true&w=majority
deve ser transformada em
mongodb+srv://benilton:SenhaReal@cluster0-s8gg0.mongodb.net
e armazenada numa variável chamada myurl
na sua sessão R:
myurl = "mongodb+srv://dbenilton:senhadificil@cluster0-s8gg0.mongodb.net"
me315mongodb
e, dentro deste, uma coleção chamada diamantes
.library(mongolite)
con = mongo(collection = "diamantes", db = "me315mongodb", url=myurl)
Exiba o conteúdo de con
. Explore o método insert()
e descreva textualmente que tipo de objeto o argumento data
pode receber.
Explore o conjunto de dados diamonds
que é distribuído por meio do pacote ggplot2
. Quantas observações e quantas colunas possui este conjunto de dados?
library(tidyverse)
ggplot2::diamonds
## # A tibble: 53,940 x 10
## carat cut color clarity depth table price x y z
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
## 1 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43
## 2 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31
## 3 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31
## 4 0.290 Premium I VS2 62.4 58 334 4.2 4.23 2.63
## 5 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75
## 6 0.24 Very Good J VVS2 62.8 57 336 3.94 3.96 2.48
## 7 0.24 Very Good I VVS1 62.3 57 336 3.95 3.98 2.47
## 8 0.26 Very Good H SI1 61.9 55 337 4.07 4.11 2.53
## 9 0.22 Fair E VS2 65.1 61 337 3.87 3.78 2.49
## 10 0.23 Very Good H VS1 59.4 61 338 4 4.05 2.39
## # … with 53,930 more rows
dim(ggplot2::diamonds)
## [1] 53940 10
con$insert(ggplot2::diamonds)
## List of 5
## $ nInserted : num 53940
## $ nMatched : num 0
## $ nRemoved : num 0
## $ nUpserted : num 0
## $ writeErrors: list()
cut
seja igual a Premium
e custem menos de USD 1.000,00. Armazene o resultado na variável p1000a
. Quantos diamantes ‘premium’ custam menos de 1.000 dólares na sua amostra?p1000a = con$find('{"cut":"Premium", "price":{"$lt": 1000}}')
p1000a %>% as_tibble()
## # A tibble: 3,200 x 10
## carat cut color clarity depth table price x y z
## <dbl> <chr> <chr> <chr> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
## 1 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31
## 2 0.290 Premium I VS2 62.4 58 334 4.2 4.23 2.63
## 3 0.22 Premium F SI1 60.4 61 342 3.88 3.84 2.33
## 4 0.2 Premium E SI2 60.2 62 345 3.79 3.75 2.27
## 5 0.32 Premium E I1 60.9 58 345 4.38 4.42 2.68
## 6 0.24 Premium I VS1 62.5 57 355 3.97 3.94 2.47
## 7 0.290 Premium F SI1 62.4 58 403 4.24 4.26 2.65
## 8 0.22 Premium E VS2 61.6 58 404 3.93 3.89 2.41
## 9 0.22 Premium D VS2 59.3 62 404 3.91 3.88 2.31
## 10 0.3 Premium J SI2 59.3 61 405 4.43 4.38 2.61
## # … with 3,190 more rows
cut
, clarity
e price
. Armazene o resultado na variável p1000b
.p1000b = con$find('{"cut":"Premium", "price":{"$lt": 1000}}',
fields='{"_id":0, "cut":1, "clarity":1, "price":1}')
p1000b %>% as_tibble()
## # A tibble: 3,200 x 3
## cut clarity price
## <chr> <chr> <int>
## 1 Premium SI1 326
## 2 Premium VS2 334
## 3 Premium SI1 342
## 4 Premium SI2 345
## 5 Premium I1 345
## 6 Premium VS1 355
## 7 Premium SI1 403
## 8 Premium VS2 404
## 9 Premium VS2 404
## 10 Premium SI2 405
## # … with 3,190 more rows
p1000c
.p1000c = con$find('{"cut":"Premium", "price":{"$lt": 1000}}',
fields='{"_id":0, "cut":1, "clarity":1, "price":1}',
sort='{"price":-1}', limit=5)
p1000c %>% as_tibble()
## # A tibble: 5 x 3
## cut clarity price
## <chr> <chr> <int>
## 1 Premium VS2 999
## 2 Premium VS2 999
## 3 Premium VS2 999
## 4 Premium VVS2 999
## 5 Premium VS1 999
system.time(caro <- con$find(sort='{"price":-1}', limit=400))
## user system elapsed
## 0.005 0.001 0.428
caro %>% head
## carat cut color clarity depth table price x y z
## 1 2.29 Premium I VS2 60.8 60 18823 8.50 8.47 5.16
## 2 2.00 Very Good G SI1 63.5 56 18818 7.90 7.97 5.04
## 3 1.51 Ideal G IF 61.7 55 18806 7.37 7.41 4.56
## 4 2.07 Ideal G SI2 62.5 55 18804 8.20 8.13 5.11
## 5 2.00 Very Good H SI1 62.8 57 18803 7.95 8.00 5.01
## 6 2.29 Premium I SI1 61.8 59 18797 8.52 8.45 5.24
price
.con$index('{"price": -1}')
## v key._id key.price name ns
## 1 2 1 NA _id_ me315mongodb.diamantes
## 2 2 NA -1 price_-1 me315mongodb.diamantes
system.time(caro2 <- con$find(sort='{"price":-1}', limit=400))
## user system elapsed
## 0.006 0.001 0.288
caro2 %>% head
## carat cut color clarity depth table price x y z
## 1 2.29 Premium I VS2 60.8 60 18823 8.50 8.47 5.16
## 2 2.00 Very Good G SI1 63.5 56 18818 7.90 7.97 5.04
## 3 1.51 Ideal G IF 61.7 55 18806 7.37 7.41 4.56
## 4 2.07 Ideal G SI2 62.5 55 18804 8.20 8.13 5.11
## 5 2.00 Very Good H SI1 62.8 57 18803 7.95 8.00 5.01
## 6 2.29 Premium I SI1 61.8 59 18797 8.52 8.45 5.24
Observação: Diferenças entre os tempos de execução das questões serão mínimas, assumindo que aconteçam. Estas diferenças poderão ser notadas mais explicitamente se o servidor do MongoDB for local. Pelo fato de estarmos utilizando um servidor público via internet, a maior parte do tempo mensurado é devido à conexão propriamente dita.
iterate()
para trabalhar com lotes de linhas do banco de dados. Armazene o resultado de iterate()
na variável it
. Observe que o método iterate
possui um argumento limit
, que determina o número máximo de documentos da coleção a serem considerados. Explore a documentação do método e realize a iteração apenas para diamantes de cut="Premium"
, ordenando por preço (de maneira decresente). Aplique o método batch(n)
, com n=53
, para determinar as estatísticas suficientes da média de preços. Saiba que, muito provavelmente, ao chegar ao fim do banco de dados, o número de observações no seu subconjunto será inferior ao tamanho do lote.# se o lote terá tamanho 53, quantos lotes no total serão necessários?
n = 53
themax = con$count()
lotes = ceiling(themax/n)
it = con$iterate('{"cut":"Premium"}', sort='{"price":-1}', limit=themax)
lst = vector('list', lotes)
i = 1
fim = FALSE
while(!fim){
x = it$batch(n)
x = do.call('rbind', lapply(x, as.data.frame))
if (nrow(x) < n) fim=TRUE
lst[[i]] = data.frame(soma=sum(x$price), n=nrow(x))
i = i+1
}
lst = lst[1:(i-1)]
lst = do.call('rbind', lst)
lst %>% summarise(media=sum(soma)/sum(n))
## media
## 1 4584.258
aggregate()
para determinar o número de diamantes e o respectivo preço médio, estratificando pela variável cut
. Renomeie as colunas para que sejam, respectivamente, tipo
, n
e media
. Use o ggplot2
para apresentar um gráfico de barras com o preço.res = con$aggregate('[{"$group":
{"_id":"$cut",
"n":{"$sum":1},
"media":{"$avg":"$price"}
}
}]')
names(res) = c("tipo", "n", "media")
library(ggplot2)
ggplot(res, aes(tipo, media)) + geom_bar(stat='identity') + theme_bw()
export()
, exporte o banco de dados para um arquivo no seu computador (chamado meusdiamantes.json
). O arquivo deve ser gravado no formato JSON. Explore o arquivo e confirme a validade do seu formato.con$export(file("meusdiamantes.json"))
meusdiamantes.bson
. Explore o arquivo e confirme a validade do seu formato. Compare os tamanhos de ambos os arquivos.con$export(file("meusdiamantes.bson"), bson=TRUE)
con$drop()
con$count()
## [1] 0
import()
, importe o arquivo BSON criado por você diretamente para o banco de dados. Conte o número de observações existentes após a importação.con$import(file('meusdiamantes.bson'), bson=TRUE)
## [1] 53940
con$count()
## [1] 53940
con$drop()