在 MongoDB (rmongodb) 中附加 BSON 数组

Posted

技术标签:

【中文标题】在 MongoDB (rmongodb) 中附加 BSON 数组【英文标题】:Appending BSON arrays in MongoDB (rmongodb) 【发布时间】:2013-01-23 21:22:41 【问题描述】:

我找到了this 有关如何使用$push 运算符向数组添加新值的信息。但是,我似乎无法使用 rmongodb

假设我们在数据库中有以下文档

_id : 7      51005201f8ab44f1690f9526
tags : 4     
    1 : 2    a
    2 : 2    b
    3 : 2    c

我想向数组tags 添加一个值。这是我尝试过的:

q <- mongo.bson.from.list(list(tags="a"))

试一试

这里我尝试使用$push 运算符

代码

bnew <- mongo.bson.from.list(list("$push"=list("tags"="d")))

> mongo.update(mongo=con, ns, criteria=q, objNew=bnew)
[1] FALSE

日志文件

Thu Jan 24 16:42:27 [initandlisten] MongoDB starting : pid=6260 port=27017 dbpath=\data\db\ 64-bit host=ASHB-109C-02
Thu Jan 24 16:42:27 [initandlisten] db version v2.2.2, pdfile version 4.5
Thu Jan 24 16:42:27 [initandlisten] git version: d1b43b61a5308c4ad0679d34b262c5af9d664267
Thu Jan 24 16:42:27 [initandlisten] build info: windows sys.getwindowsversion(major=6, minor=1, build=7601, platform=2, service_pack='Service Pack 1') BOOST_LIB_VERSION=1_49
Thu Jan 24 16:42:27 [initandlisten] options:  logpath: "log_1.txt" 
Thu Jan 24 16:42:27 [initandlisten] journal dir=/data/db/journal
Thu Jan 24 16:42:27 [initandlisten] recover : no journal files present, no recovery needed
Thu Jan 24 16:42:27 [initandlisten] waiting for connections on port 27017
Thu Jan 24 16:42:27 [websvr] admin web console waiting for connections on port 28017
Thu Jan 24 16:42:36 [initandlisten] connection accepted from 127.0.0.1:52419 #1 (1 connection now open)
Thu Jan 24 16:42:44 [conn1]  __test.test Assertion failure x == _nfields src\mongo\db\jsobj.cpp 1250
Thu Jan 24 16:42:44 [conn1] mongod.exe    ...\src\mongo\util\stacktrace.cpp(161)                           mongo::printStackTrace+0x3e
Thu Jan 24 16:42:44 [conn1] mongod.exe    ...\src\mongo\util\assert_util.cpp(109)                          mongo::verifyFailed+0xdc
Thu Jan 24 16:42:44 [conn1] mongod.exe    ...\src\mongo\db\jsobj.cpp(1250)                                 mongo::BSONIteratorSorted::BSONIteratorSorted+0xf3
Thu Jan 24 16:42:44 [conn1] mongod.exe    ...\src\mongo\db\ops\update_internal.cpp(906)                    mongo::ModSetState::createNewFromMods+0xa3
Thu Jan 24 16:42:44 [conn1] mongod.exe    ...\src\mongo\db\ops\update.cpp(370)                             mongo::_updateObjects+0x15a2
Thu Jan 24 16:42:44 [conn1] mongod.exe    ...\src\mongo\db\instance.cpp(573)                               mongo::receivedUpdate+0x60d
Thu Jan 24 16:42:44 [conn1] mongod.exe    ...\src\mongo\db\instance.cpp(437)                               mongo::assembleResponse+0x626
Thu Jan 24 16:42:44 [conn1] mongod.exe    ...\src\mongo\db\db.cpp(192)                                     mongo::MyMessageHandler::process+0xf5
Thu Jan 24 16:42:44 [conn1] mongod.exe    ...\src\mongo\util\net\message_server_port.cpp(86)               mongo::pms::threadRun+0x59a
Thu Jan 24 16:42:44 [conn1] mongod.exe    ...\src\third_party\boost\libs\thread\src\win32\thread.cpp(180)  boost::`anonymous namespace'::thread_start_function+0x21
Thu Jan 24 16:42:44 [conn1] mongod.exe    f:\dd\vctools\crt_bld\self_64_amd64\crt\src\threadex.c(314)      _callthreadstartex+0x17
Thu Jan 24 16:42:44 [conn1] mongod.exe    f:\dd\vctools\crt_bld\self_64_amd64\crt\src\threadex.c(292)      _threadstartex+0x7f
Thu Jan 24 16:42:44 [conn1] kernel32.dll                                                                   BaseThreadInitThunk+0xd
Thu Jan 24 16:42:44 [conn1] update __test.test query:  tags: "a"  update:  $push:  tags: "d"   nscanned:1 keyUpdates:0 exception: assertion src\mongo\db\jsobj.cpp:1250 locks(micros) w:398335 399ms
Thu Jan 24 16:42:48 CTRL_CLOSE_EVENT signal
Thu Jan 24 16:42:48 [consoleTerminate] got CTRL_CLOSE_EVENT, will terminate after current cmd ends
Thu Jan 24 16:42:48 [consoleTerminate] now exiting
Thu Jan 24 16:42:48 dbexit: 
Thu Jan 24 16:42:48 [consoleTerminate] shutdown: going to close listening sockets...
Thu Jan 24 16:42:48 [consoleTerminate] closing listening socket: 496
Thu Jan 24 16:42:48 [consoleTerminate] closing listening socket: 516
Thu Jan 24 16:42:48 [consoleTerminate] shutdown: going to flush diaglog...
Thu Jan 24 16:42:48 [consoleTerminate] shutdown: going to close sockets...
Thu Jan 24 16:42:48 [consoleTerminate] shutdown: waiting for fs preallocator...
Thu Jan 24 16:42:48 [consoleTerminate] shutdown: lock for final commit...
Thu Jan 24 16:42:48 [consoleTerminate] shutdown: final commit...
Thu Jan 24 16:42:48 [conn1] end connection 127.0.0.1:52419 (0 connections now open)
Thu Jan 24 16:42:48 [consoleTerminate] shutdown: closing all files...
Thu Jan 24 16:42:48 [consoleTerminate] closeAllFiles() finished
Thu Jan 24 16:42:48 [consoleTerminate] journalCleanup...
Thu Jan 24 16:42:48 [consoleTerminate] removeJournalFiles
Thu Jan 24 16:42:48 [consoleTerminate] shutdown: removing fs lock...
Thu Jan 24 16:42:48 dbexit: really exiting now

尝试 2

这里我尝试使用$addToSet 运算符

代码

buf <- mongo.bson.buffer.create()
mongo.bson.buffer.start.object(buf, "$addToSet")
mongo.bson.buffer.start.object(buf, name="tags")
mongo.bson.buffer.start.array(buf, "$each")
values <- list("d", "e", "f")
for (ii in seq(along=values)) 
    mongo.bson.buffer.append(
        buf=buf, 
        name=as.character(ii),
        value=values[[ii]]
    )

mongo.bson.buffer.finish.object(buf)
mongo.bson.buffer.finish.object(buf)
mongo.bson.buffer.finish.object(buf)
bnew <- mongo.bson.from.buffer(buf)
bnew

> mongo.update(mongo=con, ns, criteria=q, objNew=bnew)
[1] FALSE

日志文件

Thu Jan 24 16:43:52 [initandlisten] MongoDB starting : pid=4184 port=27017 dbpath=\data\db\ 64-bit host=ASHB-109C-02
Thu Jan 24 16:43:52 [initandlisten] db version v2.2.2, pdfile version 4.5
Thu Jan 24 16:43:52 [initandlisten] git version: d1b43b61a5308c4ad0679d34b262c5af9d664267
Thu Jan 24 16:43:52 [initandlisten] build info: windows sys.getwindowsversion(major=6, minor=1, build=7601, platform=2, service_pack='Service Pack 1') BOOST_LIB_VERSION=1_49
Thu Jan 24 16:43:52 [initandlisten] options:  logpath: "log_2.txt" 
Thu Jan 24 16:43:52 [initandlisten] journal dir=/data/db/journal
Thu Jan 24 16:43:52 [initandlisten] recover : no journal files present, no recovery needed
Thu Jan 24 16:43:52 [initandlisten] waiting for connections on port 27017
Thu Jan 24 16:43:52 [websvr] admin web console waiting for connections on port 28017
Thu Jan 24 16:43:57 [initandlisten] connection accepted from 127.0.0.1:52435 #1 (1 connection now open)
Thu Jan 24 16:44:27 [conn1]  __test.test Assertion failure x == _nfields src\mongo\db\jsobj.cpp 1250
Thu Jan 24 16:44:28 [conn1] mongod.exe    ...\src\mongo\util\stacktrace.cpp(161)                           mongo::printStackTrace+0x3e
Thu Jan 24 16:44:28 [conn1] mongod.exe    ...\src\mongo\util\assert_util.cpp(109)                          mongo::verifyFailed+0xdc
Thu Jan 24 16:44:28 [conn1] mongod.exe    ...\src\mongo\db\jsobj.cpp(1250)                                 mongo::BSONIteratorSorted::BSONIteratorSorted+0xf3
Thu Jan 24 16:44:28 [conn1] mongod.exe    ...\src\mongo\db\ops\update_internal.cpp(906)                    mongo::ModSetState::createNewFromMods+0xa3
Thu Jan 24 16:44:28 [conn1] mongod.exe    ...\src\mongo\db\ops\update.cpp(370)                             mongo::_updateObjects+0x15a2
Thu Jan 24 16:44:28 [conn1] mongod.exe    ...\src\mongo\db\instance.cpp(573)                               mongo::receivedUpdate+0x60d
Thu Jan 24 16:44:28 [conn1] mongod.exe    ...\src\mongo\db\instance.cpp(437)                               mongo::assembleResponse+0x626
Thu Jan 24 16:44:28 [conn1] mongod.exe    ...\src\mongo\db\db.cpp(192)                                     mongo::MyMessageHandler::process+0xf5
Thu Jan 24 16:44:28 [conn1] mongod.exe    ...\src\mongo\util\net\message_server_port.cpp(86)               mongo::pms::threadRun+0x59a
Thu Jan 24 16:44:28 [conn1] mongod.exe    ...\src\third_party\boost\libs\thread\src\win32\thread.cpp(180)  boost::`anonymous namespace'::thread_start_function+0x21
Thu Jan 24 16:44:28 [conn1] mongod.exe    f:\dd\vctools\crt_bld\self_64_amd64\crt\src\threadex.c(314)      _callthreadstartex+0x17
Thu Jan 24 16:44:28 [conn1] mongod.exe    f:\dd\vctools\crt_bld\self_64_amd64\crt\src\threadex.c(292)      _threadstartex+0x7f
Thu Jan 24 16:44:28 [conn1] kernel32.dll                                                                   BaseThreadInitThunk+0xd
Thu Jan 24 16:44:28 [conn1] update __test.test query:  tags: "a"  update:  $addToSet:  tags:  $each: [ "d", "e", "f" ]    nscanned:1 keyUpdates:0 exception: assertion src\mongo\db\jsobj.cpp:1250 locks(micros) w:390312 390ms
Thu Jan 24 16:44:33 [conn1] end connection 127.0.0.1:52435 (0 connections now open)
Thu Jan 24 16:44:37 CTRL_CLOSE_EVENT signal
Thu Jan 24 16:44:37 [consoleTerminate] got CTRL_CLOSE_EVENT, will terminate after current cmd ends
Thu Jan 24 16:44:37 [consoleTerminate] now exiting
Thu Jan 24 16:44:37 dbexit: 
Thu Jan 24 16:44:37 [consoleTerminate] shutdown: going to close listening sockets...
Thu Jan 24 16:44:37 [consoleTerminate] closing listening socket: 496
Thu Jan 24 16:44:37 [consoleTerminate] closing listening socket: 500
Thu Jan 24 16:44:37 [consoleTerminate] shutdown: going to flush diaglog...
Thu Jan 24 16:44:37 [consoleTerminate] shutdown: going to close sockets...
Thu Jan 24 16:44:37 [consoleTerminate] shutdown: waiting for fs preallocator...
Thu Jan 24 16:44:37 [consoleTerminate] shutdown: lock for final commit...
Thu Jan 24 16:44:37 [consoleTerminate] shutdown: final commit...
Thu Jan 24 16:44:37 [consoleTerminate] shutdown: closing all files...
Thu Jan 24 16:44:37 [consoleTerminate] closeAllFiles() finished
Thu Jan 24 16:44:37 [consoleTerminate] journalCleanup...
Thu Jan 24 16:44:37 [consoleTerminate] removeJournalFiles
Thu Jan 24 16:44:37 [consoleTerminate] shutdown: removing fs lock...
Thu Jan 24 16:44:37 dbexit: really exiting now

我在这里做错了什么?


其他信息

对于那些感兴趣的人:这里是生成示例文档的代码

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)


# CONNECTION
db  <- "__test" 
ns  <- paste(db, "test", sep=".")
con <- mongo.create(db=db)

# ENSURE EMPTY DB
mongo.remove(mongo=con, ns=ns)

# INSERT
buf <- mongo.bson.buffer.create()
mongo.bson.buffer.start.array(buf, name="tags")
values <- list("a", "b", "c")
for (ii in seq(along=values)) 
    mongo.bson.buffer.append(
        buf=buf, 
        name=as.character(ii), 
        value=values[[ii]]
    )
   
mongo.bson.buffer.finish.object(buf)
mongo.bson.buffer.finish.object(buf)
b <- mongo.bson.from.buffer(buf)
mongo.insert(mongo=con, ns=ns, b=b)

编辑 2013-01-29

正如来自 10gen 的Tad Marshall 在他对我的bug report 的评论中所建议的那样,我重新运行了插入文档的代码,MongoDB 服务器以--objcheck 模式运行(验证 BSON 结构)并且瞧:服务器由于断言失败,不会让我插入文档。如果我在没有--objcheck 标志的情况下运行服务器,则插入成功(但这可能只是因为没有进行验证)。

请注意,我尝试将两个不同版本的数组放在 tags 中,因为我的初始代码生成了一个文档,恕我直言,它与 MongoDB 的索引约定不同步:

(可能)无效文档

这就是我上面的做法。我注意到我没有确保数组索引以0 开头。插入此文档将失败(请参阅下面的日志文件)

buf <- mongo.bson.buffer.create()
mongo.bson.buffer.start.array(buf, name="tags")
values <- list("a", "b", "c")
for (ii in seq(along=values)) 
    mongo.bson.buffer.append(
        buf=buf, 
        name=as.character(ii), 
        value=values[[ii]]
    )
   
mongo.bson.buffer.finish.object(buf) # finish array 'tags'
mongo.bson.buffer.finish.object(buf) # finish buffer
b <- mongo.bson.from.buffer(buf)
> b
    tags : 4     
        1 : 2    a
        2 : 2    b
        3 : 2    c

有效文件

我确保索引以0 开头,所以这绝对应该是一个有效的 BSON 文档。但是插入此文档也会失败(请参阅下面的日志文件)

buf <- mongo.bson.buffer.create()
mongo.bson.buffer.start.array(buf, name="tags")
values <- list("a", "b", "c")
for (ii in seq(along=values)) 
    mongo.bson.buffer.append(
        buf=buf, 
        name=as.character(ii-1), 
        value=values[[ii]]
    )
   
mongo.bson.buffer.finish.object(buf) # finish array 'tags'
mongo.bson.buffer.finish.object(buf) # finish buffer
b <- mongo.bson.from.buffer(buf)
b
mongo.insert(mongo=con, ns=ns, b=b)
> b
    tags : 4     
        0 : 2    a
        1 : 2    b
        2 : 2    c

日志文件

Tue Jan 29 14:20:46 [initandlisten] MongoDB starting : pid=6440 port=27017 

[...]

Tue Jan 29 14:20:59 [initandlisten] connection accepted from 127.0.0.1:62137 #1 (1 connection now open)
Tue Jan 29 14:21:03 [conn1] Assertion: 10307:Client Error: bad object in message
Tue Jan 29 14:21:04 [conn1] mongod.exe    ...\src\mongo\util\stacktrace.cpp(161)                           mongo::printStackTrace+0x3e
Tue Jan 29 14:21:04 [conn1] mongod.exe    ...\src\mongo\util\assert_util.cpp(154)                          mongo::msgasserted+0xc1
Tue Jan 29 14:21:04 [conn1] mongod.exe    ...\src\mongo\db\dbmessage.h(205)                                mongo::DbMessage::nextJsObj+0x103
Tue Jan 29 14:21:04 [conn1] mongod.exe    ...\src\mongo\db\instance.cpp(784)                               mongo::receivedInsert+0xdb
Tue Jan 29 14:21:04 [conn1] mongod.exe    ...\src\mongo\db\instance.cpp(434)                               mongo::assembleResponse+0x607
Tue Jan 29 14:21:04 [conn1] mongod.exe    ...\src\mongo\db\db.cpp(192)                                     mongo::MyMessageHandler::process+0xf5
Tue Jan 29 14:21:04 [conn1] mongod.exe    ...\src\mongo\util\net\message_server_port.cpp(86)               mongo::pms::threadRun+0x59a
Tue Jan 29 14:21:04 [conn1] mongod.exe    ...\src\third_party\boost\libs\thread\src\win32\thread.cpp(180)  boost::`anonymous namespace'::thread_start_function+0x21
Tue Jan 29 14:21:04 [conn1] mongod.exe    f:\dd\vctools\crt_bld\self_64_amd64\crt\src\threadex.c(314)      _callthreadstartex+0x17
Tue Jan 29 14:21:04 [conn1] mongod.exe    f:\dd\vctools\crt_bld\self_64_amd64\crt\src\threadex.c(292)      _threadstartex+0x7f
Tue Jan 29 14:21:04 [conn1] kernel32.dll                                                                   BaseThreadInitThunk+0xd
Tue Jan 29 14:21:04 [conn1] insert __test.test keyUpdates:0 exception: Client Error: bad object in message code:10307  0ms
Tue Jan 29 14:21:07 [conn1] Assertion: 10307:Client Error: bad object in message
Tue Jan 29 14:21:07 [conn1] mongod.exe    ...\src\mongo\util\stacktrace.cpp(161)                           mongo::printStackTrace+0x3e
Tue Jan 29 14:21:07 [conn1] mongod.exe    ...\src\mongo\util\assert_util.cpp(154)                          mongo::msgasserted+0xc1
Tue Jan 29 14:21:07 [conn1] mongod.exe    ...\src\mongo\db\dbmessage.h(205)                                mongo::DbMessage::nextJsObj+0x103
Tue Jan 29 14:21:07 [conn1] mongod.exe    ...\src\mongo\db\instance.cpp(784)                               mongo::receivedInsert+0xdb
Tue Jan 29 14:21:07 [conn1] mongod.exe    ...\src\mongo\db\instance.cpp(434)                               mongo::assembleResponse+0x607
Tue Jan 29 14:21:07 [conn1] mongod.exe    ...\src\mongo\db\db.cpp(192)                                     mongo::MyMessageHandler::process+0xf5
Tue Jan 29 14:21:07 [conn1] mongod.exe    ...\src\mongo\util\net\message_server_port.cpp(86)               mongo::pms::threadRun+0x59a
Tue Jan 29 14:21:07 [conn1] mongod.exe    ...\src\third_party\boost\libs\thread\src\win32\thread.cpp(180)  boost::`anonymous namespace'::thread_start_function+0x21
Tue Jan 29 14:21:07 [conn1] mongod.exe    f:\dd\vctools\crt_bld\self_64_amd64\crt\src\threadex.c(314)      _callthreadstartex+0x17
Tue Jan 29 14:21:07 [conn1] mongod.exe    f:\dd\vctools\crt_bld\self_64_amd64\crt\src\threadex.c(292)      _threadstartex+0x7f
Tue Jan 29 14:21:07 [conn1] kernel32.dll                                                                   BaseThreadInitThunk+0xd
Tue Jan 29 14:21:07 [conn1] insert __test.test keyUpdates:0 exception: Client Error: bad object in message code:10307  0ms

【问题讨论】:

【参考方案1】:

哦,我现在正在打自己。我没有仔细查看您创建文档的方式。当您只需要一个来完成您开始的数组时,您有两个 mongo.bson.finish.object() 调用。你不需要调用它来完成一个 BSON。 mongo.bson.from.buffer() 进行必要的内务处理。这是我没有足够仔细地阅读您的代码的错。当文档的初始插入是问题时,我认为这是您的更新失败。对于将来的问题,如果您的示例更易于阅读,将会有所帮助。例如,这将构建文档:

library('rmongodb')
m = mongo.create()
ns = '__test.test'
mongo.insert(m, ns, list(tags=c('a', 'b', 'c'))

但是,您可能正在粘贴真实世界的代码,所以我明白其中的复杂性。一切都很酷。只是因为错过了这一点而自责,并让你大吃一惊。问候

【讨论】:

绝对没问题!!一旦我意识到我一开始就无法与“不断调试”作斗争,我只是接受了这个事实并养成了习惯;-) 另外:通过尝试系统地追踪“幻象错误”。所以,真的没有必要道歉,一切都很好。至于代码:我明白你的意思,我会记住这一点。感谢您的响应! 不客气。我很高兴你的努力是“富有成效的”,但我认为你让我轻松了! :) 干杯 这是 mongo-c-driver 的缺陷。如果您不在子对象或数组中,则 bson_append_finish_object() 应该返回错误代码并且不附加任何内容。我会修复它并在那里做一个拉取请求。但是,在我更新驱动程序之前将有一段时间。最近 mongo-c-driver 发生了很多变化,当我进行“重大”更新(最终)时,我必须保持同步。 对。好吧,大多数时候 mongo.bson.from.list() 会做正确的事情,因为它是在本机代码中,所以它会比在 R 中编码的必须解释的东西快得多。我计划尽快改进 mongo.bson.from.list() 以便在其元素未命名时创建一个数组。目前,最好使用 mongo.bson.from.list() 并且只在缓冲区不正确时使用。 关于 BSON 验证,目前没有办法做到这一点。 bson_validate() 可能是对 mongo-c-driver 的一个有价值的补充。我会让它超过 10 代人。【参考方案2】:

Rappster,这两个示例都适用于我的开发机器,但我在运行 mongod 2.1.0 的调试版本时有点过时了。

由于您使用示例代码使服务器崩溃,这是 10 代人想要了解的内容。你介意去https://jira.mongodb.org/secure/Dashboard.jspa 报告这个错误吗?

谢谢,

杰拉德·林兹利

【讨论】:

感谢您的回答,我很高兴这样做! 感谢您抽出宝贵时间提交报告。 好吧,没什么大不了的>>感谢您投入时间和精力来开发驱动程序! 嘿,杰拉德,你的假设是正确的:好像我正在制作无效的 BSON 文档:-/ 知道为什么吗?在这方面:我注意到 rmongodb 允许您创建索引值不符合 MongoDB 约定的数组(例如,第一个索引值可以是 1 而不是 0)。这是故意的吗? 啊!我刚刚添加了另一个应该解决问题的答案。就索引而言,“4”不会弄乱 rmongodb 或我编写的其他两个驱动程序(MongoMatlabDriver 和 MongoDelphiDriver)。但是服务器的 --objcheck 不喜欢它,也许它可能会弄乱其他驱动程序之一。最好遵守约定。

以上是关于在 MongoDB (rmongodb) 中附加 BSON 数组的主要内容,如果未能解决你的问题,请参考以下文章

使用 rmongodb 在 R 中运行高级 MongoDB 查询

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

对 MongoDB 3 的 rmongodb 支持

使用 rmongodb 时,在 mongoDB 中看不到集合

MongoDB 和 rmongodb。获取查找的大小而不是返回所有结果

如何使用 rmongodb 将数据框插入 mongodb