0

我正在使用以下代码从 mongo 获取一些东西:

class BlockingMongoFetcher
  include MongoConfig

  def initialize
    configure
    @connection = Mongo::Connection.new(@server, @port)
    @collection = init_collection(@connection)
  end

  def fetch(value)
    mongo_cursor = @collection.find({ KEY => value.to_s })

    if mongo_cursor.count == 0
      # do stuff
      return nil
    end

    if mongo_cursor.count > 1
      # do stuff
    end

    mongo_cursor.first
  end
end

init_collection 只是从连接中获取数据库和集合对象。在 fetch 方法中,我使用 count 方法来检查是否有结果。因为我得到了一个 0,应该有 1 个项目,所以我在 gem 中将以下代码添加到 Cursor 类的 count 方法中:

if response['n'].to_i == 0
  require "ruby-debug"
  debugger
  puts "stop here"
end

( 响应 = @db.command(command) )

在调试器内

@db.command(command)['n'].to_i

返回 1。如果我在 fetch 方法中调用 count 两次(一次不使用输出),一切都很好。我错过了什么吗?缓冲区或缓存问题?然而,这似乎不是确定性的……它只发生在大约 50% 的运行中。Mongodb 是 2.0.2 和 Ruby 1.9.3p125。

谢谢你的帮助!

4

2 回答 2

0

嗯,意想不到的解决方案:

为了插入测试数据,我在规范中使用了以下语句

collection.insert @hash

insert 方法有一个选项 :safe,请参阅API。使用默认值 (false),mongodb 将其异步存储并继续执行代码。如果您事后立即查询,这可能会导致奇怪的行为,例如该值尚未在数据库中。只需使用

collection.insert @hash, :safe => true
于 2012-05-14T14:51:03.270 回答
0

我怀疑您在某处有错误,并建议您检查游标查询的结果(例如 p collection.find(query).to_a)与集合(例如 p collection.find.to_a)。以下适用于 Ruby 1.9.3、Mongo 2.0.4、mongo-ruby-driver 1.6.2。我希望它有所帮助,也许您可​​以验证它是否也适用于您并且可以收敛到解决方案。

MongoConfig.rb

require "mongo"

KEY = 'my_key'

module MongoConfig
  SERVER = 'localhost'
  PORT = Mongo::Connection::DEFAULT_PORT
  DB = 'my_db'
  COLLECTION = 'my_collection'

  attr_accessor :db, :collection

  def configure
    @server = SERVER
    @port = PORT
  end

  def init_collection(connection)
    @db = connection[MongoConfig::DB]
    @collection = @db[MongoConfig::COLLECTION]
    return @collection
  end

end

blocking_mongo_fetcher_test.rb

$LOAD_PATH.unshift(File.expand_path("..", __FILE__))

require "test-unit"
require "MongoConfig"
require "BlockingMongoFetcher"

class BlockingMongoFetcherTest < Test::Unit::TestCase

  def setup
    clear_collection
  end

  def clear_collection
    Mongo::Connection.new[MongoConfig::DB][MongoConfig::COLLECTION].remove
  end

  def count_various_ways_and_cursor_twice_test
    value = 'my name'
    query = {KEY => value}
    count_command = {'count' => MongoConfig::COLLECTION, 'query' => { KEY => value} }
    fetcher = BlockingMongoFetcher.new

    assert_equal(0, fetcher.collection.count) # collection count
    assert_equal(0, fetcher.collection.find(query).count) # cursor count
    assert_equal(0, fetcher.db.command(count_command)['n'].to_i) # db command count
    assert_nil(fetcher.fetch(value))

    fetcher.collection.insert({KEY => value})
    fetcher.collection.insert({KEY => 'x'})

    assert_equal(2, fetcher.collection.count) # collection count
    assert_equal(1, fetcher.collection.find(query).count) # cursor count
    assert_equal(1, fetcher.db.command(count_command)['n'].to_i) # db command count
    assert_equal(value, fetcher.fetch(value)[KEY])

    cursor = fetcher.collection.find(query)
    assert_equal(1, cursor.count) # check once
    assert_equal(1, cursor.count) # check twice
  end

  test "basic test" do
    count_various_ways_and_cursor_twice_test
  end

  test "repeated test" do
    100.times do
      clear_collection
      count_various_ways_and_cursor_twice_test
    end
  end

end
于 2012-04-23T17:19:32.367 回答