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, index_name, fields) ⇒ Object
Create a new index on
collection_name
namedindex_name
. -
#db_command(selector) ⇒ Object
DB commands need to be ordered, so selector must be an OrderedHash (or a Hash with only one element).
-
#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. - #full_coll_name(collection_name) ⇒ Object
-
#index_information(collection_name) ⇒ Object
Return an array of hashes, one for each index on
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. -
#query(collection, query) ⇒ Object
Returns a Cursor over the query results.
-
#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. -
#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 |
# 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 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.
155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/mongo/db.rb', line 155 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(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.
290 291 292 293 |
# File 'lib/mongo/db.rb', line 290 def close @socket.close if @socket @socket = nil 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.
230 231 232 233 |
# File 'lib/mongo/db.rb', line 230 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”.
176 177 178 179 180 |
# File 'lib/mongo/db.rb', line 176 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.
185 186 187 188 189 |
# File 'lib/mongo/db.rb', line 185 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
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/mongo/db.rb', line 128 def connect_to_master close if @socket @host = @port = nil @nodes.detect { |hp| @host, @port = *hp begin @socket = TCPSocket.new(@host, @port) # 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 => ex close if @socket end @socket } raise "error: failed to connect to any given host:port" unless @socket end |
#connected? ⇒ Boolean
295 296 297 |
# File 'lib/mongo/db.rb', line 295 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.
353 354 355 356 357 358 359 360 |
# File 'lib/mongo/db.rb', line 353 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) 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.
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/mongo/db.rb', line 204 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, index_name, fields) ⇒ Object
Create a new index on collection_name
named index_name
. fields
should be an array of field names. Normally called by Collection#create_index.
402 403 404 405 406 407 408 409 410 |
# File 'lib/mongo/db.rb', line 402 def create_index(collection_name, index_name, fields) sel = {:name => index_name, :ns => full_coll_name(collection_name)} field_h = {} fields.each { |f| field_h[f] = 1 } sel[:key] = field_h @semaphore.synchronize { send_to_db(InsertMessage.new(@name, SYSTEM_INDEX_COLLECTION, sel)) } 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.
450 451 452 453 454 455 456 457 458 459 460 |
# File 'lib/mongo/db.rb', line 450 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 |
#drop_collection(name) ⇒ Object
Drop collection name
. Returns true
on success or if the collection does not exist, false
otherwise.
237 238 239 240 241 242 243 |
# File 'lib/mongo/db.rb', line 237 def drop_collection(name) return true unless collection_names.include?(full_coll_name(name)) coll = collection(name) coll.drop_indexes # Mongo requires that we drop indexes manually 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.
364 365 366 367 368 369 370 |
# File 'lib/mongo/db.rb', line 364 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 |
#full_coll_name(collection_name) ⇒ Object
435 436 437 |
# File 'lib/mongo/db.rb', line 435 def full_coll_name(collection_name) "#{@name}.#{collection_name}" end |
#index_information(collection_name) ⇒ Object
Return an array of hashes, one for each index on collection_name
. Normally called by Collection#index_information. Each hash contains:
- :name
-
Index name
- :keys
-
Hash whose keys are the names of the fields that make up the key and values are integers.
- :ns
-
Namespace; same as
collection_name
.
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 |
# File 'lib/mongo/db.rb', line 381 def index_information(collection_name) sel = {:ns => full_coll_name(collection_name)} query(Collection.new(self, SYSTEM_INDEX_COLLECTION), Query.new(sel)).collect { |row| h = {:name => row['name']} raise "Name of index on return from db was nil. Coll = #{full_coll_name(collection_name)}" unless h[:name] h[:keys] = row['key'] raise "Keys for index on return from db was nil. Coll = #{full_coll_name(collection_name)}" unless h[:keys] h[:ns] = row['ns'] raise "Namespace for index on return from db was nil. Coll = #{full_coll_name(collection_name)}" unless h[:ns] h[:ns].sub!(/.*\./, '') raise "Error: ns != collection" unless h[:ns] == collection_name h } 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.
415 416 417 418 419 420 421 422 423 |
# File 'lib/mongo/db.rb', line 415 def insert_into_db(collection_name, objects) @semaphore.synchronize { objects.collect { |o| o = @pk_factory.create_pk(o) if @pk_factory send_to_db(InsertMessage.new(@name, collection_name, o)) o } } end |
#logout ⇒ Object
Deauthorizes use for this database for this connection.
169 170 171 172 |
# File 'lib/mongo/db.rb', line 169 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.
277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/mongo/db.rb', line 277 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.
269 270 271 272 273 |
# File 'lib/mongo/db.rb', line 269 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.
440 441 442 443 |
# File 'lib/mongo/db.rb', line 440 def ok?(doc) ok = doc['ok'] ok.kind_of?(Numeric) && ok.to_i == 1 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.
309 310 311 |
# File 'lib/mongo/db.rb', line 309 def query(collection, query) Cursor.new(self, collection, query) 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.
322 323 324 325 326 |
# File 'lib/mongo/db.rb', line 322 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.
330 331 332 333 334 |
# File 'lib/mongo/db.rb', line 330 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.
342 343 344 345 346 347 348 |
# File 'lib/mongo/db.rb', line 342 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 |
#send_message(msg) ⇒ Object
Send a MsgMessage to the database.
300 301 302 |
# File 'lib/mongo/db.rb', line 300 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.
314 315 316 317 318 |
# File 'lib/mongo/db.rb', line 314 def () @semaphore.synchronize { send_to_db() } end |
#send_to_db(message) ⇒ Object
425 426 427 428 429 430 431 432 433 |
# File 'lib/mongo/db.rb', line 425 def send_to_db() connect_to_master if !connected? && @auto_reconnect begin @socket.print(.buf.to_s) 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 |