使用mong-ruby-driver将BSON直接传递给MongoDB?

时间:2012-12-27 23:33:14

标签: ruby mongodb sinatra

有没有办法将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' ]}

2 个答案:

答案 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文档和运算符。