使用R到mongoDB批量插入/更新

时间:2016-03-24 19:10:24

标签: r mongodb

我正在尝试使用各种数据框中的R将很多数据(数百万个文档)插入到mongodb中,我将在不同的时间获取这些数据。

每个数据框将具有相同的主ID,但可以具有相同或不同的属性。

如果记录存在,我想添加任何新属性并附加任何现有属性。如果记录不存在,我想创建它。

这对R有效吗?我试图使用美妙的mongolite包,但插入选项因为存在重复记录而失败。

任何指针都非常感激。

由于

伊恩

id<-LETTERS[1:5]
value1<-paste0("value1_",letters[1:5])
value2<-paste0("value2_",letters[1:5])
value3<-paste0("additional_value_1",letters[1:5])
df1<-as.data.frame(cbind(id,value1))
df2<-as.data.frame(cbind(id,value2))
df3<-as.data.frame(cbind(id,value3))

colnames(df1)<-c('_id','value1')
colnames(df2)<-c('_id','value2')
colnames(df3)<-c('_id','value1')

desired_value1<-paste0( "[",paste(paste0("'",value1,"'"),paste0("'",value3,"'"),sep=","),"]")
df4<-cbind(id,desired_value1,value2)
df4<-as.data.frame(cbind(id,desired_value1,value2))
colnames(df4)<-c("_id","value1","value2")

1 个答案:

答案 0 :(得分:1)

注意

此答案使用library(rmongodb),不再支持Cran。

这个答案在一定程度上取决于你如何获得'新'数据框架。我也无法在不知道您的设置和数据大小的情况下回答高效部分,但希望这可以帮助您入门。另外,我发现从R中插入/撤回数百万条记录到mongo中的速度非常慢。

执行此操作的一种方法是为您获得的每个新data.frame,将匹配的记录带回R并“加入/更新”它们,然后仅为这些文档更新数据库,同时附加新数据使用update / upsert查询。

我的大多数r-mongodb作品也使用library(rmongodb)

略微修改您的数据以使用id代替_id

id<-LETTERS[1:5]
value1<-paste0("value1_",letters[1:5])
value2<-paste0("value2_",letters[1:5])
value3<-paste0("additional_value_1",letters[1:5])
df1<-as.data.frame(cbind(id,value1), stringsAsFactors = F)  ## removed factor levels
df2<-as.data.frame(cbind(id,value2), stringsAsFactors = F)
df3<-as.data.frame(cbind(id,value3), stringsAsFactors = F)

colnames(df1)<-c('id','value1')
colnames(df2)<-c('id','value2')
colnames(df3)<-c('id','value1')

desired_value1<-paste0( "[",paste(paste0("'",value1,"'"),paste0("'",value3,"'"),sep=","),"]")
df4<-cbind(id,desired_value1,value2)
df4<-as.data.frame(cbind(id,desired_value1,value2))
colnames(df4)<-c("_id","value1","value2")

第一步是将其插入数据库

library(rmongodb)  ## my preferred r mongodb package 
library(jsonlite)  ## for viewing/checking results 
library(data.table) ## for fast rbind & data frame manipulation

mongo <- mongo.create()
mongo.is.connected(mongo)
# [1] TRUE

db <- "test"
coll <- "test"

bs <- mongo.bson.from.df(df1)
ns <- paste0(db, ".", coll)

## insert.batch - insert each 'row' of the df as a document
mongo.insert.batch(mongo = mongo, 
                   ns = ns, 
                   lst = bs)  
# [1] TRUE

检索所有文件以检查上传

f <- mongo.bson.from.list(list("_id" = 0))  ## to ignore the _id field
res <- mongo.find.all(mongo = mongo, ns = ns, fields = f)
toJSON(res, pretty=T)
# [
#   {
#     "id": ["A"],
#     "value1": ["value1_a"]
#   },
#   {
#     "id": ["B"],
#     "value1": ["value1_b"]
#   },
#   {
#     "id": ["C"],
#     "value1": ["value1_c"]
#   },
#   {
#     "id": ["D"],
#     "value1": ["value1_d"]
#   },
#   {
#     "id": ["E"],
#     "value1": ["value1_e"]
#   }
# ] 

现在,如果我们想将df2$value2添加到这些文档中,我们可以将它们带回R来操作它们,然后更新数据库

qry <- list("id" = list("$in" = df2$id))
## mongo shell query: db.test.find({"id" : { "$in" : ["A", "B", ..., ]}})
qry <- mongo.bson.from.list(qry)
f <- list("_id" = 0)
res <- mongo.find.all(mongo = mongo, 
                      ns = ns,
                      query = qry,
                      fields = f)

dt_res <- rbindlist(res)

## set our df2 to data.table, and join onto dt_res
setDT(df2)

## add a new row to df2, with a new id, to check the update.upsert works
df2 <- rbindlist(list(df2, data.table(id = "Z", value2 = "value2_z")))

dt_res <- dt_res[ df2, on="id"]  ## left join to keep our 'z' row
dt_res
#    id   value1   value2
# 1:  A value1_a value2_a
# 2:  B value1_b value2_b
# 3:  C value1_c value2_c
# 4:  D value1_d value2_d
# 5:  E value1_e value2_e
# 6:  Z       NA value2_z

我们现在可以使用udpate and upsert

使用这些新值更新数据库
for(i in 1:nrow(dt_res)){

  crit <- mongo.bson.from.list(list("id" = dt_res[i, id]))
  d <- c(dt_res[i, ])
  mongo.update(mongo = mongo, 
               ns = ns, 
               criteria = crit, 
               objNew = d, 
               flags = c(mongo.update.upsert))    
}

通过返回所有内容来检查documnet是否已被更新

f <- mongo.bson.from.list(list("_id" = 0))  ## to ignore the _id field
res <- mongo.find.all(mongo = mongo, ns = ns, fields = f)
toJSON(res, pretty=T)

# [
#   {
#     "id": ["A"],
#     "value1": ["value1_a"],
#     "value2": ["value2_a"]
#   },
#   {
#     "id": ["B"],
#     "value1": ["value1_b"],
#     "value2": ["value2_b"]
#   },
#   {
#     "id": ["C"],
#     "value1": ["value1_c"],
#     "value2": ["value2_c"]
#   },
#   {
#     "id": ["D"],
#     "value1": ["value1_d"],
#     "value2": ["value2_d"]
#   },
#   {
#     "id": ["E"],
#     "value1": ["value1_e"],
#     "value2": ["value2_e"]
#   },
#   {
#     "id": ["Z"],
#     "value1": {},
#     "value2": ["value2_z"]
#   }
# ] 

请注意,这包括我们新的'z'id