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 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.
292 293 294 295 296 297 298 |
# File 'lib/mongo/db.rb', line 292 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 => ex close if @socket end @socket } raise "error: failed to connect to any given host:port" unless @socket end |
#connected? ⇒ Boolean
300 301 302 |
# File 'lib/mongo/db.rb', line 300 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.
358 359 360 361 362 363 364 365 |
# File 'lib/mongo/db.rb', line 358 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.
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, 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.
407 408 409 410 411 412 413 414 415 |
# File 'lib/mongo/db.rb', line 407 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.
456 457 458 459 460 461 462 463 464 465 466 |
# File 'lib/mongo/db.rb', line 456 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.
239 240 241 242 243 244 245 |
# File 'lib/mongo/db.rb', line 239 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.
369 370 371 372 373 374 375 |
# File 'lib/mongo/db.rb', line 369 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.
253 254 255 256 257 |
# File 'lib/mongo/db.rb', line 253 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.
265 266 267 |
# File 'lib/mongo/db.rb', line 265 def error? error != nil end |
#full_coll_name(collection_name) ⇒ Object
441 442 443 |
# File 'lib/mongo/db.rb', line 441 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
.
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/mongo/db.rb', line 386 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.
420 421 422 423 424 425 426 427 428 |
# File 'lib/mongo/db.rb', line 420 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.
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.
279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/mongo/db.rb', line 279 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.
271 272 273 274 275 |
# File 'lib/mongo/db.rb', line 271 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.
446 447 448 449 |
# File 'lib/mongo/db.rb', line 446 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.
314 315 316 |
# File 'lib/mongo/db.rb', line 314 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.
327 328 329 330 331 |
# File 'lib/mongo/db.rb', line 327 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.
335 336 337 338 339 |
# File 'lib/mongo/db.rb', line 335 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.
347 348 349 350 351 352 353 |
# File 'lib/mongo/db.rb', line 347 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.
305 306 307 |
# File 'lib/mongo/db.rb', line 305 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.
319 320 321 322 323 |
# File 'lib/mongo/db.rb', line 319 def () @semaphore.synchronize { send_to_db() } end |
#send_to_db(message) ⇒ Object
430 431 432 433 434 435 436 437 438 439 |
# File 'lib/mongo/db.rb', line 430 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 |