有没有办法将BSON对象直接传递到mongo-ruby-driver中的.find()
?
目前我有一个基本的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()
返回结果。
示例网址: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' ]}
答案 0 :(得分:0)
您的问题与解析JSON或Ruby(Regexp)有关,而不是与BSON有关。您的原始问题会直接跳到BSON而导致混淆。使用当前的Ruby驱动程序,BSON不会直接暴露给应用程序编写器,而是尽可能自然地映射到Ruby对象。
JSON受到严格限制,可以安全地进行解析。为Regexp添加解析将超出此范围。
您可以使用Kernel#eval不安全地执行您想要的操作。这将解析你的Regexp,但它也会解析exec,系统,反引号等。对于任意用户输入的公共应用程序,你将不得不做一些更安全的事情。
另请注意,以下几行之间的差异,突出了Ruby和MongoDB的语义:
{ interests: [ 'fishing', 'golf' ] }
如果它们完全是['钓鱼','高尔夫'],则上述内容完全匹配兴趣。不多也不少,没有其他秩序。
{ interests: { '$in' => [ 'fishing', 'golf' ] } }
如果兴趣包括“钓鱼”或“高尔夫”,任何订单,任何职位,任何额外内容,则上述内容符合利益。请注意,字符串键'$ in'需要原始值=>语法。
希望这有助于您的理解,请随时通过澄清问题进行跟进。
以下是一个工作示例。
myapp.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
红宝石 - 我。 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
答案 1 :(得分: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文档和运算符。