更新 MongoDB 中的多个文档 (rmongodb)

Posted

技术标签:

【中文标题】更新 MongoDB 中的多个文档 (rmongodb)【英文标题】:Update multiple documents in MongoDB (rmongodb) 【发布时间】:2013-01-14 22:38:40 【问题描述】:

我偶然发现了一些关于函数处理更新的问题 (mongo.update())。

免责声明

由于我还在熟悉MongoDB 和rmongodb 包,所以插图中的问题很可能是由于我缺乏知识;-)

准备工作

确保已加载包

pkg <- "rmongodb"
lib <- file.path(R.home(), "library")
if (!suppressWarnings(require(pkg, lib.loc=lib, character.only=TRUE))) 
    install.packages(pkg, lib=lib)
    require(pkg, lib.loc=lib, character.only=TRUE)

全局变量

db      <- "__test"
ns.0    <- "user"
ns      <- paste(db, ns.0, sep=".")
con     <- mongo.create(db=db)

创建数据库的初始状态

确保空数据库

mongo.remove(mongo=con, ns=ns, 
    criteria=mongo.bson.from.list(lst=list(namefirst="John")))

插入文档

fields      <- list(namefirst="John", namelast="Doe")
b           <- mongo.bson.from.list(lst=fields)
mongo.insert(mongo=con, ns=ns, b=b)
if (is.null(mongo.find.one(mong=con, ns=ns, query=b))) 
    stop("Something went wrong")

更新/更新文档

criteria    <- list(namefirst="John", namelast="Smith")
fields      <- list(namefirst="John", namelast="Smith", age=30)
b           <- mongo.bson.from.list(lst=fields)
crit        <- mongo.bson.from.list(lst=criteria)
mongo.update(mongo=con, ns=ns, criteria=crit, objNew=b, 
    flags=mongo.update.upsert)
if (is.null(mongo.find.one(mong=con, ns=ns, query=b))) 
    stop("Something went wrong")

列出可用文档

criteria    <- list(namefirst="John")
crit        <- mongo.bson.from.list(lst=criteria)
cursor      <- mongo.find(mongo=con, ns=ns, query=crit)
out         <- NULL
while (mongo.cursor.next(cursor=cursor)) 
    bson <- mongo.cursor.value(cursor=cursor)    
    out <- c(out, list(bson))

> out
[[1]]
    _id : 7      50f484fe3c3b8b8e3daa72e0
    namefirst : 2    John
    namelast : 2     Doe

[[2]]
    _id : 7      50f484ff3c3b8b8e3daa72e1
    namefirst : 2    John
    namelast : 2     Smith
    age : 1      30.000000

此时,集合中有两个文档,这是我们所期望的。

问题 #1:使用默认标志值更新 (0)

criteria    <- list(namefirst="John")
fields      <- list(age=99)
b           <- mongo.bson.from.list(lst=fields)
crit        <- mongo.bson.from.list(lst=criteria)
mongo.update(mongo=con, ns=ns, criteria=crit, objNew=b)
cursor      <- mongo.find(mongo=con, ns=ns, query=crit)
out         <- NULL
while (mongo.cursor.next(cursor=cursor)) 
    bson <- mongo.cursor.value(cursor=cursor)
    out <- c(out, list(mongo.bson.to.list(bson)))

if (out[[1]]$age != 99) 
    stop("Something went wrong")

> out
[[1]]
[[1]]$`_id`
 $oid : "50f484ff3c3b8b8e3daa72e1" 

[[1]]$namefirst
[1] "John"

[[1]]$namelast
[1] "Smith"

[[1]]$age
[1] 30

执行更新后,只剩下一个文档了。

问题 #2:使用“multi”标志值更新 (2)

从头开始,因为以前的更新似乎损坏了数据库:

确保空数据库

mongo.remove(mongo=con, ns=ns, 
    criteria=mongo.bson.from.list(lst=list(namefirst="John")))

插入文档

fields      <- list(namefirst="John", namelast="Doe")
b           <- mongo.bson.from.list(lst=fields)
mongo.insert(mongo=con, ns=ns, b=b)
if (is.null(mongo.find.one(mong=con, ns=ns, query=b))) 
    stop("Something went wrong")

更新/更新文档

criteria    <- list(namefirst="John", namelast="Smith")
fields      <- list(namefirst="John", namelast="Smith", age=30)
b           <- mongo.bson.from.list(lst=fields)
crit        <- mongo.bson.from.list(lst=criteria)
mongo.update(mongo=con, ns=ns, criteria=crit, objNew=b, 
    flags=mongo.update.upsert)
if (is.null(mongo.find.one(mong=con, ns=ns, query=b))) 
    stop("Something went wrong")

尝试更新多个文档。我在这里追求的是在两个集合中将age 的值更改为99

criteria    <- list(namefirst="John")
fields      <- list(age=99)
b           <- mongo.bson.from.list(lst=fields)
crit        <- mongo.bson.from.list(lst=criteria)
mongo.update(mongo=con, ns=ns, criteria=crit, objNew=b, 
    flags=mongo.update.multi)
cursor      <- mongo.find(mongo=con, ns=ns, query=crit)
out         <- NULL
while (mongo.cursor.next(cursor=cursor)) 
    bson <- mongo.cursor.value(cursor=cursor)
    out <- c(out, list(mongo.bson.to.list(bson)))

调查当前数据库状态

> out
[[1]]
[[1]]$`_id`
 $oid : "50f485cd3c3b8b8e3daa72e2" 

[[1]]$namefirst
[1] "John"

[[1]]$namelast
[1] "Doe"


[[2]]
[[2]]$`_id`
 $oid : "50f485ce3c3b8b8e3daa72e3" 

[[2]]$namefirst
[1] "John"

[[2]]$namelast
[1] "Smith"

[[2]]$age
[1] 30

> sapply(out, function(ii) ii$age)
[[1]]
NULL

[[2]]
[3] 30

我希望两个文档都有age = 99

【问题讨论】:

【参考方案1】:

在这两个“潜在错误”中,您都将记录更新为仅包含年龄字段的记录。您的记录仍然存在,但它们没有 namefirst 字段(或除 age 和 _id 之外的任何其他字段)来匹配后面的查询。 mongo.update() 通常替换整个文档,而不是选定的字段。您的第二个示例可以这样编码:

criteria    <- list(namefirst="John")
fields      <- list(age=99)
b           <- mongo.bson.from.list(lst=list('$set'=fields))
crit        <- mongo.bson.from.list(lst=criteria)
mongo.update(mongo=con, ns=ns, criteria=crit, objNew=b, 
    flags=mongo.update.multi)

只设置所需的字段。请参阅http://docs.mongodb.org/manual/applications/update 了解更多信息。

顺便说一句,虽然你的例子很清楚,但你可以写得更简洁:

mongo.update(con, ns, list(namefirst="John"),
                      list('$set'=list(age=99)), mongo.update.multi)

【讨论】:

太好了,非常感谢 - 又学到了一些东西!并不是说听起来不尊重或将整个事情标记为“可能的错误”;-) 感谢您抽出宝贵的时间! 不客气...没问题。抱歉,我无法抗拒围绕“潜在错误”的讽刺引用:) 只是想说+1,这节省了一天。在您回答之前,我一生都无法弄清楚如何更新任何内容。对于某些 mongo 相关任务,复杂的示例在网上很少见。再次感谢。

以上是关于更新 MongoDB 中的多个文档 (rmongodb)的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB 中的位置 $ 运算符似乎不会更新多个文档

MongoDb:如何根据每个字段的值更新多个文档中的字段值?

MongoDb:如何根据每个字段的值更新多个文档中的字段值?

使用 arrayFilters 更新 MongoDB 中的嵌套子文档

如何在 R 中安装 RMongo 包

在没有 for 循环的情况下更新多个文档 MongoDB