1

有没有办法将 BSON 对象直接传递到.find()mongo-ruby-driver 中?

目前我有一个基本的 sinatra 应用程序,它采用 URL 编码的 JSON 并将其解析为 .find() 但理想情况下我想直接给它 BSON:

require 'sinatra'
require 'mongo'
require 'json'

include Mongo
db = MongoClient.new().db('test')

get '/' do
  if request[:query]
    query = JSON.parse(CGI::unescape(request[:query]))
    db.collection('test_collection').find(query).to_a.to_json
  end
end

所以基本上有一些类似的东西BSON.parse(url-encoded-query)并且能够将它传递给.find()返回结果。

示例 URL:http://localhost:4567/?query=%7B%20%22name%22%20%3A%20%22john%20doe%22%20%7D
当前查询:{ "name" : "john doe" }
BSON 查询:{ name: /.*john.*/, interests: [ 'fishing', 'golf' ]}我想工作

4

2 回答 2

0

您的问题与解析 JSON 或 Ruby(Regexp)有关,而不是与 BSON 有关。您最初的问题直接跳到 BSON 会引起混淆。使用当前的 Ruby 驱动程序,BSON 不直接暴露给应用程序编写者,而是尽可能自然地映射到 Ruby 对象和映射到 Ruby 对象。

JSON 受到严格限制且解析安全。为 Regexp 添加解析超出了此范围。

你可以使用 Kernel#eval 不安全地做你想做的事。这将解析您的 Regexp,但它也会解析 exec、system、反引号等。对于具有任意用户输入的公共应用程序,您必须做一些更安全的事情。

另请注意,以下行之间的差异突出了 Ruby 和 MongoDB 的语义:

{ interests: [ 'fishing', 'golf' ] }

如果它们完全是 ['fishing', 'golf'],则上述内容完全匹配兴趣。没有更多,没有更少,没有其他顺序。

{ interests: { '$in' => [ 'fishing', 'golf' ] } }

如果兴趣有“钓鱼”或“高尔夫”、任何顺序、任何位置、任何额外内容,则上述匹配兴趣。请注意,字符串键 '$in' 需要原始 => 语法。

希望这有助于您的理解,请随时跟进澄清问题。

以下是一个工作示例。

我的应用程序.rb

require 'sinatra'
require 'mongo'
require 'json'

include Mongo
db = MongoClient.new().db('test')

get '/' do
  if request[:query]
    query = eval CGI::unescape(request[:query])
    docs = db.collection('test_collection').find(query).to_a.to_json
    "docs=#{docs}"
  end
end

myapp_test.rb

require 'myapp'
require 'test/unit'
require 'rack/test'
require 'open-uri'
ENV['RACK_ENV'] = 'test'

class MyAppTest < Test::Unit::TestCase
  include Rack::Test::Methods

  def setup
    @db ||= Mongo::MongoClient.new['test']
    @coll ||= @db['test_collection']
    @coll.remove
    @coll.insert({name: 'john doe', interests: [ 'fishing', 'golf' ]})
  end

  def app
    Sinatra::Application
  end

  def query_test(query)
    uri = "http://localhost:4567/?query=#{URI::encode(query)}"
    puts "uri=#{uri}"
    get uri
    puts last_response.body
    assert_match(/^docs=/, last_response.body)
  end

  def test_john_doe
    query_test("{ name: 'john doe'}")
  end

  def test_regexp
    query_test("{ name: /.*john.*/, interests: [ 'fishing', 'golf' ]}")
  end
end

红宝石-I。myapp_test.rb

Run options:

# Running tests:

uri=http://localhost:4567/?query=%7B%20name:%20/.*john.*/,%20interests:%20[%20'fishing',%20'golf'%20]%7D
docs=[{"_id":{"$oid": "50e9e60029daeb0be1000001"},"name":"john doe","interests":["fishing","golf"]}]
.uri=http://localhost:4567/?query=%7B%20name:%20'john%20doe'%7D
docs=[{"_id":{"$oid": "50e9e60129daeb0be1000002"},"name":"john doe","interests":["fishing","golf"]}]
.

Finished tests in 0.065822s, 30.3850 tests/s, 60.7700 assertions/s.

2 tests, 4 assertions, 0 failures, 0 errors, 0 skips
于 2013-01-06T21:13:35.550 回答
0

以下测试脚本演示了如何使用 $elemMatch 运算符作为投影。请注意,Collection#find 方法为 "selector" 形式参数和 "opts" :fields 选项获取任意文档。

MongoDB 文档映射到/来自 Ruby Hash 对象,这些文档可以完全包含 MongoDB 运算符。

elemmatch_projection.rb

#!/usr/bin/env ruby

# Ruby translation of example from http://docs.mongodb.org/manual/reference/projection/elemMatch/
require 'mongo'
coll = Mongo::MongoClient.new['test']['students']
coll.remove
coll.insert({
  zipcode: 63109,
  dependents: [
    { name: "john", school: 102, age: 10 },
    { name: "jess", school: 102, age: 11 },
    { name: "jeff", school: 108, age: 15 }
  ]
})
p coll.find( { zipcode: 63109 }, :fields => { dependents: { '$elemMatch' => { school: 102 } } } ).to_a

ruby elemmatch_projection.rb

[{"_id"=>BSON::ObjectId('50eab29929daeb05ae000001'), "dependents"=>[{"name"=>"john", "school"=>102, "age"=>10}]}]

这是另一个答案,因为 OP 已经明确澄清了这个问题。

希望这可以帮助您了解如何在 Ruby 中使用 MongoDB 文档和运算符。

于 2013-01-07T16:36:55.600 回答