Class: Mongo::DB

Inherits:
Object
  • Object
show all
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

Instance Method Summary collapse

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 Connection#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.



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/mongo/db.rb', line 114

def initialize(db_name, nodes, options={})
  case db_name
  when Symbol, String
  else
    raise TypeError, "db_name must be a string or symbol"
  end

  [" ", ".", "$", "/", "\\"].each do |invalid_char|
    if db_name.include? invalid_char
      raise InvalidName, "database names cannot contain the character '#{invalid_char}'"
    end
  end
  if db_name.empty?
    raise InvalidName, "database name cannot be the empty string"
  end

  @name, @nodes = db_name, nodes
  @strict = options[:strict]
  @pk_factory = options[:pk]
  @slave_ok = options[:slave_ok] && @nodes.length == 1 # only OK if one node
  @auto_reconnect = options[:auto_reconnect]
  @semaphore = Object.new
  @semaphore.extend Mutex_m
  @socket = nil
  connect_to_master
end

Instance Attribute Details

#hostObject (readonly)

Host to which we are currently connected.



52
53
54
# File 'lib/mongo/db.rb', line 52

def host
  @host
end

#nameObject (readonly)

The name of the database.



49
50
51
# File 'lib/mongo/db.rb', line 49

def name
  @name
end

#nodesObject (readonly)

An array of [host, port] pairs.



57
58
59
# File 'lib/mongo/db.rb', line 57

def nodes
  @nodes
end

#pk_factoryObject

A primary key factory object (or nil). See the README.doc file or DB#new for details.



67
68
69
# File 'lib/mongo/db.rb', line 67

def pk_factory
  @pk_factory
end

#portObject (readonly)

Port to which we are currently connected.



54
55
56
# File 'lib/mongo/db.rb', line 54

def port
  @port
end

#socketObject (readonly)

The database’s socket. For internal (and Cursor) use only.



60
61
62
# File 'lib/mongo/db.rb', line 60

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.



43
44
45
# File 'lib/mongo/db.rb', line 43

def strict=(value)
  @strict = value
end

Instance Method Details

#_synchronize(&block) ⇒ Object



550
551
552
# File 'lib/mongo/db.rb', line 550

def _synchronize &block
  @semaphore.synchronize &block
end

#adminObject



244
245
246
# File 'lib/mongo/db.rb', line 244

def admin
  Admin.new(self)
end

#authenticate(username, password) ⇒ Object

Returns true if username has password in SYSTEM_USER_COLLECTION. name is username, password is plaintext password.



169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/mongo/db.rb', line 169

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

Returns:

  • (Boolean)


63
# File 'lib/mongo/db.rb', line 63

def auto_reconnect?; @auto_reconnect; end

#closeObject

Close the connection to the database.



331
332
333
334
335
336
337
# File 'lib/mongo/db.rb', line 331

def close
  if @socket
    s = @socket
    @socket = nil
    s.close
  end
end

#collection(name) ⇒ Object Also known as: []

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.



251
252
253
254
# File 'lib/mongo/db.rb', line 251

def collection(name)
  return Collection.new(self, name) if !strict? || collection_names.include?(name)
  raise "Collection #{name} doesn't exist. Currently in strict mode."
end

#collection_namesObject

Returns an array of collection names in this database.



189
190
191
192
193
# File 'lib/mongo/db.rb', line 189

def collection_names
  names = collections_info.collect { |doc| doc['name'] || '' }
  names = names.delete_if {|name| name.index(@name).nil? || name.index('$')}
  names.map {|name| name.sub(@name + '.', '')}
end

#collectionsObject

Retruns an array of Collection instances, one for each collection in this database.



197
198
199
200
201
# File 'lib/mongo/db.rb', line 197

def collections
  collection_names.map do |collection_name|
    Collection.new(self, collection_name)
  end
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.



206
207
208
209
210
# File 'lib/mongo/db.rb', line 206

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_masterObject



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/mongo/db.rb', line 141

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

      @slave_ok || is_master
    rescue SocketError, SystemCallError, IOError => ex
      close if @socket
      false
    end
  }
  raise "error: failed to connect to any given host:port" unless @socket
end

#connected?Boolean

Returns:

  • (Boolean)


339
340
341
# File 'lib/mongo/db.rb', line 339

def connected?
  @socket != nil
end

#count(collection_name, selector = {}) ⇒ Object

DEPRECATED - use Collection.find(selector).count() instead



406
407
408
409
# File 'lib/mongo/db.rb', line 406

def count(collection_name, selector={})
  warn "DB#count is deprecated and will be removed. Please use Collection.find(selector).count instead."
  collection(collection_name).find(selector).count()
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 is true, specifies the maximum number of bytes. If false, specifies the initial extent of the collection.

:max

Max number of records in a capped collection. Optional.



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/mongo/db.rb', line 225

def create_collection(name, options={})
  # First check existence
  if collection_names.include?(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(options || {}))
  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 Mongo::ASCENDING or Mongo::DESCENDING. Normally called by Collection#create_index. If unique is true the index will enforce a uniqueness constraint.



473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
# File 'lib/mongo/db.rb', line 473

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
  }
  _synchronize {
    send_to_db(InsertMessage.new(@name, SYSTEM_INDEX_COLLECTION, false, sel))
  }
  name
end

#db_command(selector, use_admin_db = false) ⇒ 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.



538
539
540
541
542
543
544
545
546
547
548
# File 'lib/mongo/db.rb', line 538

def db_command(selector, use_admin_db=false)
  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, use_admin_db).next_object
end

#dereference(dbref) ⇒ Object

Dereference a DBRef, getting the document it points to.



412
413
414
# File 'lib/mongo/db.rb', line 412

def dereference(dbref)
  collection(dbref.namespace).find_one("_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.



259
260
261
262
263
# File 'lib/mongo/db.rb', line 259

def drop_collection(name)
  return true unless collection_names.include?(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.



445
446
447
448
449
450
451
# File 'lib/mongo/db.rb', line 445

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

#errorObject

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.



271
272
273
274
275
# File 'lib/mongo/db.rb', line 271

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.

Returns:

  • (Boolean)


283
284
285
# File 'lib/mongo/db.rb', line 283

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.

Raises:



420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/mongo/db.rb', line 420

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 OperationFailure, "eval failed: #{doc['errmsg']}"
end

#full_coll_name(collection_name) ⇒ Object



523
524
525
# File 'lib/mongo/db.rb', line 523

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).



458
459
460
461
462
463
464
465
# File 'lib/mongo/db.rb', line 458

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 the _ids of the inserted documents.



496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
# File 'lib/mongo/db.rb', line 496

def insert_into_db(collection_name, objects)
  _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

#logoutObject

Deauthorizes use for this database for this connection.



183
184
185
186
# File 'lib/mongo/db.rb', line 183

def logout
  doc = db_command(:logout => 1)
  raise "error logging out: #{doc.inspect}" unless ok?(doc)
end

#masterObject

Returns a string of the form “host:port” that points to the master database. Works even if this is the master database.



318
319
320
321
322
323
324
325
326
327
328
# File 'lib/mongo/db.rb', line 318

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.

Returns:

  • (Boolean)


310
311
312
313
314
# File 'lib/mongo/db.rb', line 310

def master?
  doc = db_command(:ismaster => 1)
  is_master = doc['ismaster']
  ok?(doc) && is_master.kind_of?(Numeric) && is_master.to_i == 1
end

#modify_in_db(collection_name, selector, obj) ⇒ Object

DEPRECATED - use Collection#update instead



389
390
391
392
# File 'lib/mongo/db.rb', line 389

def modify_in_db(collection_name, selector, obj)
  warn "DB#modify_in_db is deprecated and will be removed. Please use Collection#update instead."
  replace_in_db(collection_name, selector, obj)
end

#ok?(doc) ⇒ Boolean

Return true if doc contains an ‘ok’ field with the value 1.

Returns:

  • (Boolean)


528
529
530
531
# File 'lib/mongo/db.rb', line 528

def ok?(doc)
  ok = doc['ok']
  ok.kind_of?(Numeric) && ok.to_i == 1
end

#previous_errorObject

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.



291
292
293
294
295
296
297
298
# File 'lib/mongo/db.rb', line 291

def previous_error
  error = db_command(:getpreverror => 1)
  if error["err"]
    error
  else
    nil
  end
end

#query(collection, query, admin = false) ⇒ 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.



363
364
365
# File 'lib/mongo/db.rb', line 363

def query(collection, query, admin=false)
  Cursor.new(self, collection, query, admin)
end

#receive_full(length) ⇒ Object



343
344
345
346
347
348
349
350
351
# File 'lib/mongo/db.rb', line 343

def receive_full(length)
  message = ""
  while message.length < length do
    chunk = @socket.recv(length - message.length)
    raise "connection closed" unless chunk.length > 0
    message += chunk
  end
  message
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.



374
375
376
377
378
# File 'lib/mongo/db.rb', line 374

def remove_from_db(collection_name, selector)
  _synchronize {
    send_to_db(RemoveMessage.new(@name, collection_name, selector))
  }
end

#rename_collection(from, to) ⇒ Object

Rename collection from to to. Meant to be called by Collection#rename.



435
436
437
438
439
440
441
# File 'lib/mongo/db.rb', line 435

def rename_collection(from, to)
  oh = OrderedHash.new
  oh[:renameCollection] = "#{@name}.#{from}"
  oh[:to] = "#{@name}.#{to}"
  doc = db_command(oh, true)
  raise "Error renaming collection: #{doc.inspect}" unless ok?(doc)
end

#replace_in_db(collection_name, selector, obj) ⇒ Object

Update records in collection_name that match selector by applying obj as an update. Normally called by Collection#replace.



382
383
384
385
386
# File 'lib/mongo/db.rb', line 382

def replace_in_db(collection_name, selector, obj)
  _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.



397
398
399
400
401
402
403
# File 'lib/mongo/db.rb', line 397

def repsert_in_db(collection_name, selector, obj)
  _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_historyObject

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.



304
305
306
# File 'lib/mongo/db.rb', line 304

def reset_error_history
  db_command(:reseterror => 1)
end

#send_message(msg) ⇒ Object

Send a MsgMessage to the database.



354
355
356
# File 'lib/mongo/db.rb', line 354

def send_message(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.



368
369
370
# File 'lib/mongo/db.rb', line 368

def send_query_message(query_message)
  send_to_db(query_message)
end

#send_to_db(message) ⇒ Object



512
513
514
515
516
517
518
519
520
521
# File 'lib/mongo/db.rb', line 512

def send_to_db(message)
  connect_to_master if !connected? && @auto_reconnect
  begin
    @socket.print(message.buf.to_s)
    @socket.flush
  rescue => ex
    close
    raise ex
  end
end

#slave_ok?Boolean

Returns:

  • (Boolean)


62
# File 'lib/mongo/db.rb', line 62

def slave_ok?; @slave_ok; end

#strict?Boolean

Returns the value of the strict flag.

Returns:

  • (Boolean)


46
# File 'lib/mongo/db.rb', line 46

def strict?; @strict; end