【问题标题】:Cannot find Document with Ruby and MongoDB when using ObjectId使用 ObjectId 时找不到带有 Ruby 和 MongoDB 的文档
【发布时间】:2011-11-28 22:44:30
【问题描述】:

我有一些用 Ruby 1.9.2 补丁级别 136 编写的代码,我遇到了一个问题,当我通过原始 ruby​​ mongo 驱动程序中的 _id 执行 find 时,尝试使用一个值时得到一个 nil来自 csv 文件。代码如下:

require 'mongo'
require 'csv'
require 'bson'

# Games database
gamedb = Mongo::Connection.new("localhost", 27017).db("gamedb")
@games = gamedb.collection("games")

# Loop over CSV data.
CSV.foreach("/tmp/somedata.csv") do |row|

  puts row[0] # Puts the ObjectId

  @game = @games.find( { "_id" => row[0] } ).first  
  puts @game.inspect

end

CSV 文件如下所示:

_id,game_title,platform,upc_db_match,upc
4ecdacc339c7d7a2a6000002,TMNT,PSP,TMNT,085391157663
4ecdacc339c7d7a2a6000004,Super Mario Galaxy,Wii,Super Mario Galaxy,045496900434
4ecdacc339c7d7a2a6000005,Beowulf,PSP,Beowulf,097363473046

第一列是我已经拥有的 Mongo 中的 objectId。如果我从 mongo 命令行执行本地查找第一列中的值,我会得到我想要的数据。但是,上面的代码在 @game.inspect 调用上返回 nil。

我尝试了以下变体,它们都产生 nil:

@game = @games.find( { "_id" => row[0].to_s } ).first
@game = @games.find( { "_id" => row[0].to_s.strip } ).first

我什至尝试使用 BSON 类构建 ObjectId:

@game = @games.find( { "_id" => BSON::ObjectId(row[0]) } ).first

@game = @games.find( { "_id" => BSON::ObjectId("#{row[0]}") } ).first

两者都输出如下错误:

/Users/donnfelker/.rvm/gems/ruby-1.9.2-p136@upc-etl/gems/bson-1.4.0/lib/bson/types/object_id.rb:126:in `from_string': illegal ObjectId format: _id (BSON::InvalidObjectId)
    from /Users/donnfelker/.rvm/gems/ruby-1.9.2-p136@upc-etl/gems/bson-1.4.0/lib/bson/types/object_id.rb:26:in `ObjectId'
    from migrate_upc_from_csv.rb:14:in `block in <main>'
    from /Users/donnfelker/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/csv.rb:1768:in `each'
    from /Users/donnfelker/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/csv.rb:1202:in `block in foreach'
    from /Users/donnfelker/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/csv.rb:1340:in `open'
    from /Users/donnfelker/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/csv.rb:1201:in `foreach'
    from migrate_upc_from_csv.rb:10:in `<main>'

疯狂的是,如果我手动创建 BSON ObjectId,它就可以工作(如下所示):

@game = @games.find( { "_id" => BSON::ObjectId("4ecdacc339c7d7a2a6000004") } ).first

当我运行 @game.inspect 时,我得到了我的数据,正如我所期望的那样。但是,如果我将其更改为使用 row[0],我将得到 nil。

为什么?我究竟做错了什么?

系统详情

$ gem list

*** LOCAL GEMS ***

bson (1.4.0)
bson_ext (1.4.0)
mongo (1.4.0)

RVM 版本:rvm 1.6.9

Ruby 版本:ruby 1.9.2p136 (2010-12-25 revision 30365) [x86_64-darwin10.6.0]

Mongo 版本:

[initandlisten] db version v1.8.2, pdfile version 4.5
[initandlisten] git version: 433bbaa14aaba6860da15bd4de8edf600f56501b

再说一遍,为什么?我在这里做错了什么?谢谢!

【问题讨论】:

    标签: ruby mongodb mongodb-ruby


    【解决方案1】:

    第一行没有被读取为标题,要像这样传入:headers =&gt; true

    require 'csv'
    
    # Loop over CSV data.
    CSV.foreach("/tmp/somedata.csv", :headers => true) do |row|
    
      puts row[0] # Puts the ObjectId
    
    end
    

    如果不传入 :headers 参数可以看到第一行[0]对象是字符串“_id”:

    _id
    4ecdacc339c7d7a2a6000002
    4ecdacc339c7d7a2a6000004
    4ecdacc339c7d7a2a6000005
    

    当你包含它时,你就是金子:

    4ecdacc339c7d7a2a6000002
    4ecdacc339c7d7a2a6000004
    4ecdacc339c7d7a2a6000005
    

    【讨论】:

    • 这不是我说的吗?
    • 是的,对不起!在开始写作之前,我没有刷新页面。至少唐恩现在也有一个明确的答案,可能会更清楚一点。我在我的电脑上尝试了上述方法,可以确认我们的解决方案解决了他遇到的问题并且他可以接受答案。抱歉,如果我在这里踩到任何脚趾。
    • 接受这个作为答案,因为代码示例显示了我需要的内容。我没有使用 FasterCSV(我知道它已在 1.9.2 等等中被替换)。不过,我仍然对原版投了赞成票。谢谢!
    • 另外,值得注意的是,我从未在第一次看到 _id 标头的原因是因为我的 CSV 文件长度超过 1000 行。在我注意到 _id 之前,屏幕输出滚动了。
    【解决方案2】:

    您确定您的 CSV 解析代码没有将标题视为第一行数据并且实际上尝试执行BSON::ObjectId("_id")?错误消息有点像。尝试使用FasterCSV.foreach('/tmp/somedata.csv', :headers =&gt; true) 并使用row['_id'](IIRC 你仍然必须使用BSON::ObjectID)。

    【讨论】:

    • 感谢您的评论。我没有使用 CSV,但是您的回答确实帮助我在以下正确语法的帮助下获得了正确的最终结果。谢谢迈克尔!
    猜你喜欢
    • 2013-02-06
    • 1970-01-01
    • 2011-12-14
    • 2017-12-13
    • 1970-01-01
    • 1970-01-01
    • 2018-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多