gem mongo 1.6.2在count上返回错误的值(Cursor)

时间:2012-04-23 13:22:45

标签: ruby mongodb gem

我正在使用以下代码从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

(response = @ db.command(command))

在调试器中

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

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

感谢您的帮助!

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

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

为了插入测试数据,我在规范

中使用了以下语句
collection.insert @hash

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

collection.insert @hash, :safe => true