Class: XGen::Mongo::Driver::DB
- Inherits:
-
Object
- Object
- XGen::Mongo::Driver::DB
- Defined in:
- lib/mongo/db.rb
Overview
A Mongo database.
Constant Summary collapse
- SYSTEM_NAMESPACE_COLLECTION =
"system.namespaces"
- SYSTEM_INDEX_COLLECTION =
"system.indexes"
- SYSTEM_PROFILE_COLLECTION =
"system.profile"
- SYSTEM_USER_COLLECTION =
"system.users"
- SYSTEM_COMMAND_COLLECTION =
"$cmd"
Instance Attribute Summary collapse
-
#host ⇒ Object
readonly
Host to which we are currently connected.
-
#name ⇒ Object
readonly
The name of the database.
-
#nodes ⇒ Object
readonly
An array of [host, port] pairs.
-
#pk_factory ⇒ Object
A primary key factory object (or
nil
). -
#port ⇒ Object
readonly
Port to which we are currently connected.
-
#socket ⇒ Object
readonly
The database’s socket.
-
#strict ⇒ Object
writeonly
Strict mode enforces collection existence checks.
Instance Method Summary collapse
- #admin ⇒ Object
-
#authenticate(username, password) ⇒ Object
Returns true if
username
haspassword
inSYSTEM_USER_COLLECTION
. - #auto_reconnect? ⇒ Boolean
-
#close ⇒ Object
Close the connection to the database.
-
#collection(name) ⇒ Object
Return a collection.
-
#collection_names ⇒ Object
Returns an array of collection names.
-
#collections_info(coll_name = nil) ⇒ Object
Returns a cursor over query result hashes.
- #connect_to_master ⇒ Object
- #connected? ⇒ Boolean
-
#count(collection_name, selector = {}) ⇒ Object
Return the number of records in
collection_name
that matchselector
. -
#create_collection(name, options = {}) ⇒ Object
Create a collection.
-
#create_index(collection_name, field_or_spec, unique = false) ⇒ Object
Create a new index on
collection_name
. -
#db_command(selector) ⇒ Object
DB commands need to be ordered, so selector must be an OrderedHash (or a Hash with only one element).
-
#dereference(dbref) ⇒ Object
Dereference a DBRef, getting the document it points to.
-
#drop_collection(name) ⇒ Object
Drop collection
name
. -
#drop_index(collection_name, name) ⇒ Object
Drop index
name
fromcollection_name
. -
#error ⇒ Object
Returns the error message from the most recently executed database operation for this connection, or
nil
if there was no error. -
#error? ⇒ Boolean
Returns
true
if an error was caused by the most recently executed database operation. -
#eval(code, *args) ⇒ Object
Evaluate a JavaScript expression on MongoDB.
- #full_coll_name(collection_name) ⇒ Object
-
#index_information(collection_name) ⇒ Object
Get information on the indexes for the collection
collection_name
. -
#initialize(db_name, nodes, options = {}) ⇒ DB
constructor
Instances of DB are normally obtained by calling Mongo#db.
-
#insert_into_db(collection_name, objects) ⇒ Object
Insert
objects
intocollection_name
. -
#logout ⇒ Object
Deauthorizes use for this database for this connection.
-
#master ⇒ Object
Returns a string of the form “host:port” that points to the master database.
-
#master? ⇒ Boolean
Returns true if this database is a master (or is not paired with any other database), false if it is a slave.
-
#ok?(doc) ⇒ Boolean
Return
true
ifdoc
contains an ‘ok’ field with the value 1. -
#previous_error ⇒ Object
Get the most recent error to have occured on this database.
-
#query(collection, query) ⇒ Object
Returns a Cursor over the query results.
- #receive_full(length) ⇒ Object
-
#remove_from_db(collection_name, selector) ⇒ Object
Remove the records that match
selector
fromcollection_name
. -
#replace_in_db(collection_name, selector, obj) ⇒ Object
(also: #modify_in_db)
Update records in
collection_name
that matchselector
by applyingobj
as an update. -
#repsert_in_db(collection_name, selector, obj) ⇒ Object
Update records in
collection_name
that matchselector
by applyingobj
as an update. -
#reset_error_history ⇒ Object
Reset the error history of this database.
-
#send_message(msg) ⇒ Object
Send a MsgMessage to the database.
-
#send_query_message(query_message) ⇒ Object
Used by a Cursor to lazily send the query to the database.
- #send_to_db(message) ⇒ Object
- #slave_ok? ⇒ Boolean
-
#strict? ⇒ Boolean
Returns the value of the
strict
flag.
Constructor Details
#initialize(db_name, nodes, options = {}) ⇒ DB
Instances of DB are normally obtained by calling Mongo#db.
- db_name
-
The database name
- nodes
-
An array of [host, port] pairs. See Mongo#new, which offers a more flexible way of defining nodes.
- options
-
A hash of options.
Options:
- :strict
-
If true, collections must exist to be accessed and must not exist to be created. See #collection and #create_collection.
- :pk
-
A primary key factory object that must respond to :create_pk, which should take a hash and return a hash which merges the original hash with any primary key fields the factory wishes to inject. (NOTE: if the object already has a primary key, the factory should not inject a new key; this means that the object is being used in a repsert but it already exists.) The idea here is that when ever a record is inserted, the :pk object’s
create_pk
method will be called and the new hash returned will be inserted. - :slave_ok
-
Only used if
nodes
contains only one host/port. If false, when connecting to that host/port we check to see if the server is the master. If it is not, an error is thrown. - :auto_reconnect
-
If the connection gets closed (for example, we have a server pair and saw the “not master” error, which closes the connection), then automatically try to reconnect to the master or to the single server we have been given. Defaults to
false
.
When a DB object first connects to a pair, it will find the master instance and connect to that one. On socket error or if we recieve a “not master” error, we again find the master of the pair.
116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/mongo/db.rb', line 116 def initialize(db_name, nodes, ={}) raise "Invalid DB name \"#{db_name}\" (must be non-nil, non-zero-length, and can not contain \".\")" if !db_name || (db_name && db_name.length > 0 && db_name.include?(".")) @name, @nodes = db_name, nodes @strict = [:strict] @pk_factory = [:pk] @slave_ok = [:slave_ok] && @nodes.length == 1 # only OK if one node @auto_reconnect = [:auto_reconnect] @semaphore = Object.new @semaphore.extend Mutex_m @socket = nil connect_to_master end |
Instance Attribute Details
#host ⇒ Object (readonly)
Host to which we are currently connected.
54 55 56 |
# File 'lib/mongo/db.rb', line 54 def host @host end |
#name ⇒ Object (readonly)
The name of the database.
51 52 53 |
# File 'lib/mongo/db.rb', line 51 def name @name end |
#nodes ⇒ Object (readonly)
An array of [host, port] pairs.
59 60 61 |
# File 'lib/mongo/db.rb', line 59 def nodes @nodes end |
#pk_factory ⇒ Object
A primary key factory object (or nil
). See the README.doc file or DB#new for details.
69 70 71 |
# File 'lib/mongo/db.rb', line 69 def pk_factory @pk_factory end |
#port ⇒ Object (readonly)
Port to which we are currently connected.
56 57 58 |
# File 'lib/mongo/db.rb', line 56 def port @port end |
#socket ⇒ Object (readonly)
The database’s socket. For internal (and Cursor) use only.
62 63 64 |
# File 'lib/mongo/db.rb', line 62 def socket @socket end |
#strict=(value) ⇒ Object (writeonly)
Strict mode enforces collection existence checks. When true
, asking for a collection that does not exist or trying to create a collection that already exists raises an error.
Strict mode is off (false
) by default. Its value can be changed at any time.
45 46 47 |
# File 'lib/mongo/db.rb', line 45 def strict=(value) @strict = value end |
Instance Method Details
#authenticate(username, password) ⇒ Object
Returns true if username
has password
in SYSTEM_USER_COLLECTION
. name
is username, password
is plaintext password.
157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/mongo/db.rb', line 157 def authenticate(username, password) doc = db_command(:getnonce => 1) raise "error retrieving nonce: #{doc}" unless ok?(doc) nonce = doc['nonce'] auth = OrderedHash.new auth['authenticate'] = 1 auth['user'] = username auth['nonce'] = nonce auth['key'] = Digest::MD5.hexdigest("#{nonce}#{username}#{hash_password(username, password)}") ok?(db_command(auth)) end |
#auto_reconnect? ⇒ Boolean
65 |
# File 'lib/mongo/db.rb', line 65 def auto_reconnect?; @auto_reconnect; end |
#close ⇒ Object
Close the connection to the database.
311 312 313 314 315 316 317 |
# File 'lib/mongo/db.rb', line 311 def close if @socket s = @socket @socket = nil s.close end end |
#collection(name) ⇒ Object
Return a collection. If strict
is false, will return existing or new collection. If strict
is true, will raise an error if collection name
does not already exists.
232 233 234 235 |
# File 'lib/mongo/db.rb', line 232 def collection(name) return Collection.new(self, name) if !strict? || collection_names.include?(full_coll_name(name)) raise "Collection #{name} doesn't exist. Currently in strict mode." end |
#collection_names ⇒ Object
Returns an array of collection names. Each name is of the form “database_name.collection_name”.
178 179 180 181 182 |
# File 'lib/mongo/db.rb', line 178 def collection_names names = collections_info.collect { |doc| doc['name'] || '' } names.delete('') names end |
#collections_info(coll_name = nil) ⇒ Object
Returns a cursor over query result hashes. Each hash contains a ‘name’ string and optionally an ‘options’ hash. If coll_name
is specified, an array of length 1 is returned.
187 188 189 190 191 |
# File 'lib/mongo/db.rb', line 187 def collections_info(coll_name=nil) selector = {} selector[:name] = full_coll_name(coll_name) if coll_name query(Collection.new(self, SYSTEM_NAMESPACE_COLLECTION), Query.new(selector)) end |
#connect_to_master ⇒ Object
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/mongo/db.rb', line 129 def connect_to_master close if @socket @host = @port = nil @nodes.detect { |hp| @host, @port = *hp begin @socket = TCPSocket.new(@host, @port) @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) # Check for master. Can't call master? because it uses mutex, # which may already be in use during this call. semaphore_is_locked = @semaphore.locked? @semaphore.unlock if semaphore_is_locked is_master = master? @semaphore.lock if semaphore_is_locked break if @slave_ok || is_master rescue SocketError, SystemCallError, IOError => ex close if @socket end @socket } raise "error: failed to connect to any given host:port" unless @socket end |
#connected? ⇒ Boolean
319 320 321 |
# File 'lib/mongo/db.rb', line 319 def connected? @socket != nil end |
#count(collection_name, selector = {}) ⇒ Object
Return the number of records in collection_name
that match selector
. If selector
is nil
or an empty hash, returns the count of all records. Normally called by Collection#count.
387 388 389 390 391 392 393 394 395 |
# File 'lib/mongo/db.rb', line 387 def count(collection_name, selector={}) oh = OrderedHash.new oh[:count] = collection_name oh[:query] = selector || {} doc = db_command(oh) return doc['n'].to_i if ok?(doc) return 0 if doc['errmsg'] == "ns missing" raise "Error with count command: #{doc.inspect}" end |
#create_collection(name, options = {}) ⇒ Object
Create a collection. If strict
is false, will return existing or new collection. If strict
is true, will raise an error if collection name
already exists.
Options is an optional hash:
- :capped
-
Boolean. If not specified, capped is
false
. - :size
-
If
capped
istrue
, specifies the maximum number of bytes. Iffalse
, specifies the initial extent of the collection. - :max
-
Max number of records in a capped collection. Optional.
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/mongo/db.rb', line 206 def create_collection(name, ={}) # First check existence if collection_names.include?(full_coll_name(name)) if strict? raise "Collection #{name} already exists. Currently in strict mode." else return Collection.new(self, name) end end # Create new collection oh = OrderedHash.new oh[:create] = name doc = db_command(oh.merge( || {})) ok = doc['ok'] return Collection.new(self, name) if ok.kind_of?(Numeric) && (ok.to_i == 1 || ok.to_i == 0) raise "Error creating collection: #{doc.inspect}" end |
#create_index(collection_name, field_or_spec, unique = false) ⇒ Object
Create a new index on collection_name
. field_or_spec
should be either a single field name or a Array of [field name, direction] pairs. Directions should be specified as XGen::Mongo::ASCENDING or XGen::Mongo::DESCENDING. Normally called by Collection#create_index. If unique
is true the index will enforce a uniqueness constraint.
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 |
# File 'lib/mongo/db.rb', line 449 def create_index(collection_name, field_or_spec, unique=false) field_h = OrderedHash.new if field_or_spec.is_a?(String) || field_or_spec.is_a?(Symbol) field_h[field_or_spec.to_s] = 1 else field_or_spec.each { |f| field_h[f[0].to_s] = f[1] } end name = gen_index_name(field_h) sel = { :name => name, :ns => full_coll_name(collection_name), :key => field_h, :unique => unique } @semaphore.synchronize { send_to_db(InsertMessage.new(@name, SYSTEM_INDEX_COLLECTION, false, sel)) } name end |
#db_command(selector) ⇒ Object
DB commands need to be ordered, so selector must be an OrderedHash (or a Hash with only one element). What DB commands really need is that the “command” key be first.
Do not call this. Intended for driver use only.
514 515 516 517 518 519 520 521 522 523 524 |
# File 'lib/mongo/db.rb', line 514 def db_command(selector) if !selector.kind_of?(OrderedHash) if !selector.kind_of?(Hash) || selector.keys.length > 1 raise "db_command must be given an OrderedHash when there is more than one key" end end q = Query.new(selector) q.number_to_return = 1 query(Collection.new(self, SYSTEM_COMMAND_COLLECTION), q).next_object end |
#dereference(dbref) ⇒ Object
Dereference a DBRef, getting the document it points to.
398 399 400 |
# File 'lib/mongo/db.rb', line 398 def dereference(dbref) collection(dbref.namespace).find_first("_id" => dbref.object_id) end |
#drop_collection(name) ⇒ Object
Drop collection name
. Returns true
on success or if the collection does not exist, false
otherwise.
239 240 241 242 243 |
# File 'lib/mongo/db.rb', line 239 def drop_collection(name) return true unless collection_names.include?(full_coll_name(name)) ok?(db_command(:drop => name)) end |
#drop_index(collection_name, name) ⇒ Object
Drop index name
from collection_name
. Normally called from Collection#drop_index or Collection#drop_indexes.
421 422 423 424 425 426 427 |
# File 'lib/mongo/db.rb', line 421 def drop_index(collection_name, name) oh = OrderedHash.new oh[:deleteIndexes] = collection_name oh[:index] = name doc = db_command(oh) raise "Error with drop_index command: #{doc.inspect}" unless ok?(doc) end |
#error ⇒ Object
Returns the error message from the most recently executed database operation for this connection, or nil
if there was no error.
Note: as of this writing, errors are only detected on the db server for certain kinds of operations (writes). The plan is to change this so that all operations will set the error if needed.
251 252 253 254 255 |
# File 'lib/mongo/db.rb', line 251 def error doc = db_command(:getlasterror => 1) raise "error retrieving last error: #{doc}" unless ok?(doc) doc['err'] end |
#error? ⇒ Boolean
Returns true
if an error was caused by the most recently executed database operation.
Note: as of this writing, errors are only detected on the db server for certain kinds of operations (writes). The plan is to change this so that all operations will set the error if needed.
263 264 265 |
# File 'lib/mongo/db.rb', line 263 def error? error != nil end |
#eval(code, *args) ⇒ Object
Evaluate a JavaScript expression on MongoDB. code
should be a string or Code instance containing a JavaScript expression. Additional arguments will be passed to that expression when it is run on the server.
406 407 408 409 410 411 412 413 414 415 416 417 |
# File 'lib/mongo/db.rb', line 406 def eval(code, *args) if not code.is_a? Code code = Code.new(code) end oh = OrderedHash.new oh[:$eval] = code oh[:args] = args doc = db_command(oh) return doc['retval'] if ok?(doc) raise "Error with eval command: #{doc.inspect}" end |
#full_coll_name(collection_name) ⇒ Object
499 500 501 |
# File 'lib/mongo/db.rb', line 499 def full_coll_name(collection_name) "#{@name}.#{collection_name}" end |
#index_information(collection_name) ⇒ Object
Get information on the indexes for the collection collection_name
. Normally called by Collection#index_information. Returns a hash where the keys are index names (as returned by Collection#create_index and the values are lists of [key, direction] pairs specifying the index (as passed to Collection#create_index).
434 435 436 437 438 439 440 441 |
# File 'lib/mongo/db.rb', line 434 def index_information(collection_name) sel = {:ns => full_coll_name(collection_name)} info = {} query(Collection.new(self, SYSTEM_INDEX_COLLECTION), Query.new(sel)).each { |index| info[index['name']] = index['key'].to_a } info end |
#insert_into_db(collection_name, objects) ⇒ Object
Insert objects
into collection_name
. Normally called by Collection#insert. Returns a new array containing objects
, possibly modified by @pk_factory.
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 |
# File 'lib/mongo/db.rb', line 472 def insert_into_db(collection_name, objects) @semaphore.synchronize { if @pk_factory objects.collect! { |o| @pk_factory.create_pk(o) } else objects = objects.collect do |o| o[:_id] || o['_id'] ? o : o.merge(:_id => ObjectID.new) end end send_to_db(InsertMessage.new(@name, collection_name, true, *objects)) objects.collect { |o| o[:_id] || o['_id'] } } end |
#logout ⇒ Object
Deauthorizes use for this database for this connection.
171 172 173 174 |
# File 'lib/mongo/db.rb', line 171 def logout doc = db_command(:logout => 1) raise "error logging out: #{doc.inspect}" unless ok?(doc) end |
#master ⇒ Object
Returns a string of the form “host:port” that points to the master database. Works even if this is the master database.
298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/mongo/db.rb', line 298 def master doc = db_command(:ismaster => 1) is_master = doc['ismaster'] raise "Error retrieving master database: #{doc.inspect}" unless ok?(doc) && is_master.kind_of?(Numeric) case is_master.to_i when 1 "#@host:#@port" else doc['remote'] end end |
#master? ⇒ Boolean
Returns true if this database is a master (or is not paired with any other database), false if it is a slave.
290 291 292 293 294 |
# File 'lib/mongo/db.rb', line 290 def master? doc = db_command(:ismaster => 1) is_master = doc['ismaster'] ok?(doc) && is_master.kind_of?(Numeric) && is_master.to_i == 1 end |
#ok?(doc) ⇒ Boolean
Return true
if doc
contains an ‘ok’ field with the value 1.
504 505 506 507 |
# File 'lib/mongo/db.rb', line 504 def ok?(doc) ok = doc['ok'] ok.kind_of?(Numeric) && ok.to_i == 1 end |
#previous_error ⇒ Object
Get the most recent error to have occured on this database
Only returns errors that have occured since the last call to DB#reset_error_history - returns nil
if there is no such error.
271 272 273 274 275 276 277 278 |
# File 'lib/mongo/db.rb', line 271 def previous_error error = db_command(:getpreverror => 1) if error["err"] error else nil end end |
#query(collection, query) ⇒ Object
Returns a Cursor over the query results.
Note that the query gets sent lazily; the cursor calls #send_query_message when needed. If the caller never requests an object from the cursor, the query never gets sent.
343 344 345 |
# File 'lib/mongo/db.rb', line 343 def query(collection, query) Cursor.new(self, collection, query) end |
#receive_full(length) ⇒ Object
323 324 325 326 327 328 329 330 331 |
# File 'lib/mongo/db.rb', line 323 def receive_full(length) = "" while .length < length do chunk = @socket.recv(length - .length) raise "connection closed" unless chunk.length > 0 += chunk end end |
#remove_from_db(collection_name, selector) ⇒ Object
Remove the records that match selector
from collection_name
. Normally called by Collection#remove or Collection#clear.
356 357 358 359 360 |
# File 'lib/mongo/db.rb', line 356 def remove_from_db(collection_name, selector) @semaphore.synchronize { send_to_db(RemoveMessage.new(@name, collection_name, selector)) } end |
#replace_in_db(collection_name, selector, obj) ⇒ Object Also known as: modify_in_db
Update records in collection_name
that match selector
by applying obj
as an update. Normally called by Collection#replace.
364 365 366 367 368 |
# File 'lib/mongo/db.rb', line 364 def replace_in_db(collection_name, selector, obj) @semaphore.synchronize { send_to_db(UpdateMessage.new(@name, collection_name, selector, obj, false)) } end |
#repsert_in_db(collection_name, selector, obj) ⇒ Object
Update records in collection_name
that match selector
by applying obj
as an update. If no match, inserts (???). Normally called by Collection#repsert.
376 377 378 379 380 381 382 |
# File 'lib/mongo/db.rb', line 376 def repsert_in_db(collection_name, selector, obj) @semaphore.synchronize { obj = @pk_factory.create_pk(obj) if @pk_factory send_to_db(UpdateMessage.new(@name, collection_name, selector, obj, true)) obj } end |
#reset_error_history ⇒ Object
Reset the error history of this database
Calls to DB#previous_error will only return errors that have occurred since the most recent call to this method.
284 285 286 |
# File 'lib/mongo/db.rb', line 284 def reset_error_history db_command(:reseterror => 1) end |
#send_message(msg) ⇒ Object
Send a MsgMessage to the database.
334 335 336 |
# File 'lib/mongo/db.rb', line 334 def (msg) send_to_db(MsgMessage.new(msg)) end |
#send_query_message(query_message) ⇒ Object
Used by a Cursor to lazily send the query to the database.
348 349 350 351 352 |
# File 'lib/mongo/db.rb', line 348 def () @semaphore.synchronize { send_to_db() } end |
#send_to_db(message) ⇒ Object
488 489 490 491 492 493 494 495 496 497 |
# File 'lib/mongo/db.rb', line 488 def send_to_db() connect_to_master if !connected? && @auto_reconnect begin @socket.print(.buf.to_s) @socket.flush rescue => ex close raise ex end end |
#slave_ok? ⇒ Boolean
64 |
# File 'lib/mongo/db.rb', line 64 def slave_ok?; @slave_ok; end |
#strict? ⇒ Boolean
Returns the value of the strict
flag.
48 |
# File 'lib/mongo/db.rb', line 48 def strict?; @strict; end |