Обновление нескольких документов в MongoDB (rmongodb)

Я наткнулся на некоторые проблемы, связанные с обработкой обновлений функций (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: обновление со значением флага «несколько» (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.


person Rappster    schedule 14.01.2013    source источник


Ответы (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)
person Gerald Lindsly    schedule 15.01.2013
comment
Отлично, спасибо большое - снова чему-то научился! Я не хотел показаться неуважительным или что-то в этом роде, помечая все это возможными ошибками ;-) Спасибо, что нашли время! - person Rappster; 15.01.2013
comment
Добро пожаловать... Нет проблем. Извините, я не мог удержаться от саркастических цитат вокруг «потенциальных ошибок» :) - person Gerald Lindsly; 15.01.2013
comment
Просто хотел сказать +1, это спасло положение. Я не мог в жизни понять, как что-то обновить, пока не ответишь. Сложные примеры редки в Интернете для определенных задач, связанных с монго. Спасибо еще раз. - person Trevor Nederlof; 15.07.2015