1

.find()BSON オブジェクトをmongo-ruby-driver に直接渡す方法はありますか?

現時点では、URL エンコードされた JSON を受け取り、それを .find() に解析する基本的な sinatra アプリがありますが、理想的には直接 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

あなたの問題は、BSON よりも JSON または Ruby (Regexp) の解析に関係しています。元の質問は、BSON に直接ジャンプして混乱を引き起こします。現在の Ruby ドライバーでは、BSON はアプリケーション作成者に直接公開されませんが、Ruby オブジェクトとの間で可能な限り自然にマッピングされます。

JSON は厳密に制限されており、安全に解析できます。正規表現の解析を追加すると、これを超えて移動します。

Kernel#eval を使用して安全でない方法で実行できます。これにより正規表現が解析されますが、exec、システム、バックティックなども解析されます。任意のユーザー入力を使用するパブリック アプリケーションの場合は、より安全なことを行う必要があります。

Ruby と MongoDB の両方のセマンティクスを強調する次の行の違いにも注意してください。

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

上記は、興味が正確に [ '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

ruby -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 に答える