mongo 0.18.2 → 0.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. data/README.rdoc +37 -28
  2. data/Rakefile +19 -0
  3. data/bin/objectid_benchmark.rb +23 -0
  4. data/examples/admin.rb +7 -6
  5. data/examples/capped.rb +3 -4
  6. data/examples/cursor.rb +4 -3
  7. data/examples/gridfs.rb +3 -2
  8. data/examples/index_test.rb +10 -9
  9. data/examples/info.rb +3 -2
  10. data/examples/queries.rb +3 -2
  11. data/examples/simple.rb +3 -2
  12. data/examples/strict.rb +2 -1
  13. data/examples/types.rb +4 -3
  14. data/lib/mongo.rb +29 -12
  15. data/lib/mongo/admin.rb +17 -2
  16. data/lib/mongo/collection.rb +230 -169
  17. data/lib/mongo/connection.rb +136 -91
  18. data/lib/mongo/cursor.rb +68 -40
  19. data/lib/mongo/db.rb +247 -123
  20. data/lib/mongo/{errors.rb → exceptions.rb} +6 -5
  21. data/lib/mongo/gridfs.rb +6 -0
  22. data/lib/mongo/gridfs/grid_store.rb +142 -94
  23. data/lib/mongo/types/binary.rb +11 -1
  24. data/lib/mongo/types/code.rb +6 -1
  25. data/lib/mongo/types/dbref.rb +7 -2
  26. data/lib/mongo/types/min_max_keys.rb +58 -0
  27. data/lib/mongo/types/objectid.rb +76 -20
  28. data/lib/mongo/types/regexp_of_holding.rb +5 -0
  29. data/lib/mongo/util/bson_ruby.rb +36 -2
  30. data/lib/mongo/util/byte_buffer.rb +18 -2
  31. data/lib/mongo/util/conversions.rb +6 -5
  32. data/lib/mongo/util/ordered_hash.rb +3 -1
  33. data/lib/mongo/util/support.rb +3 -0
  34. data/lib/mongo/util/xml_to_ruby.rb +7 -0
  35. data/test/test_bson.rb +48 -0
  36. data/test/test_collection.rb +13 -0
  37. data/test/test_connection.rb +35 -0
  38. data/test/test_conversions.rb +1 -1
  39. data/test/test_cursor.rb +37 -5
  40. data/test/test_db.rb +51 -2
  41. data/test/test_db_api.rb +4 -7
  42. data/test/test_grid_store.rb +10 -0
  43. data/test/test_objectid.rb +16 -2
  44. data/test/test_ordered_hash.rb +14 -0
  45. data/test/threading/test_threading_large_pool.rb +4 -4
  46. data/test/unit/db_test.rb +43 -0
  47. metadata +5 -7
  48. data/examples/benchmarks.rb +0 -42
  49. data/examples/blog.rb +0 -76
  50. data/lib/mongo/constants.rb +0 -15
  51. data/test/mongo-qa/_common.rb +0 -8
@@ -16,16 +16,22 @@
16
16
 
17
17
  module Mongo
18
18
 
19
- # Provide administrative database methods: those having to do with
20
- # profiling and validation.
19
+ # @deprecated this class is deprecated. Methods defined here will
20
+ # henceforth be available in Mongo::DB.
21
21
  class Admin
22
22
 
23
23
  def initialize(db)
24
+ warn "The Admin class has been DEPRECATED. All admin methods now exist in DB."
24
25
  @db = db
25
26
  end
26
27
 
27
28
  # Return the current database profiling level.
29
+ #
30
+ # @return [Symbol] :off, :slow_only, or :all
31
+ #
32
+ # @deprecated please use DB#profiling_level instead.
28
33
  def profiling_level
34
+ warn "Admin#profiling_level has been DEPRECATED. Please use DB#profiling_level instead."
29
35
  oh = OrderedHash.new
30
36
  oh[:profile] = -1
31
37
  doc = @db.command(oh)
@@ -43,7 +49,10 @@ module Mongo
43
49
  end
44
50
 
45
51
  # Set database profiling level to :off, :slow_only, or :all.
52
+ #
53
+ # @deprecated please use DB#profiling_level= instead.
46
54
  def profiling_level=(level)
55
+ warn "Admin#profiling_level= has been DEPRECATED. Please use DB#profiling_level= instead."
47
56
  oh = OrderedHash.new
48
57
  oh[:profile] = case level
49
58
  when :off
@@ -60,14 +69,20 @@ module Mongo
60
69
  end
61
70
 
62
71
  # Returns an array containing current profiling information.
72
+ #
73
+ # @deprecated please use DB#profiling_info instead.
63
74
  def profiling_info
75
+ warn "Admin#profiling_info has been DEPRECATED. Please use DB#profiling_info instead."
64
76
  Cursor.new(Collection.new(@db, DB::SYSTEM_PROFILE_COLLECTION), :selector => {}).to_a
65
77
  end
66
78
 
67
79
  # Validate a named collection by raising an exception if there is a
68
80
  # problem or returning an interesting hash (see especially the
69
81
  # 'result' string value) if all is well.
82
+ #
83
+ # @deprecated please use DB#validate_collection instead.
70
84
  def validate_collection(name)
85
+ warn "Admin#validate_collection has been DEPRECATED. Please use DB#validate_collection instead."
71
86
  doc = @db.command(:validate => name)
72
87
  raise "Error with validate command: #{doc.inspect}" unless @db.ok?(doc)
73
88
  result = doc['result']
@@ -16,11 +16,23 @@
16
16
 
17
17
  module Mongo
18
18
 
19
- # A named collection of records in a database.
19
+ # A named collection of documents in a database.
20
20
  class Collection
21
21
 
22
22
  attr_reader :db, :name, :pk_factory, :hint
23
23
 
24
+ # Initialize a collection object.
25
+ #
26
+ # @param [DB] db a MongoDB database instance.
27
+ # @param [String, Symbol] name the name of the collection.
28
+ #
29
+ # @raise [InvalidName]
30
+ # if collection name is empty, contains '$', or starts or ends with '.'
31
+ #
32
+ # @raise [TypeError]
33
+ # if collection name is not a string or symbol
34
+ #
35
+ # @return [Collection]
24
36
  def initialize(db, name, pk_factory=nil)
25
37
  case name
26
38
  when Symbol, String
@@ -46,21 +58,30 @@ module Mongo
46
58
  @hint = nil
47
59
  end
48
60
 
49
- # Get a sub-collection of this collection by name.
61
+ # Return a sub-collection of this collection by name. If 'users' is a collection, then
62
+ # 'users.comments' is a sub-collection of users.
63
+ #
64
+ # @param [String] name
65
+ # the collection to return
50
66
  #
51
- # Raises InvalidName if an invalid collection name is used.
67
+ # @raise [InvalidName]
68
+ # if passed an invalid collection name
52
69
  #
53
- # :name :: the name of the collection to get
70
+ # @return [Collection]
71
+ # the specified sub-collection
54
72
  def [](name)
55
73
  name = "#{self.name}.#{name}"
56
74
  return Collection.new(db, name) if !db.strict? || db.collection_names.include?(name)
57
75
  raise "Collection #{name} doesn't exist. Currently in strict mode."
58
76
  end
59
77
 
60
- # Set hint fields to use and return +self+. hint may be a single field
61
- # name, array of field names, or a hash (preferably an OrderedHash).
62
- # May be +nil+.
63
- def hint=(hint)
78
+ # Set a hint field for query optimizer. Hint may be a single field
79
+ # name, array of field names, or a hash (preferably an [OrderedHash]).
80
+ # If using MongoDB > 1.1, you probably don't ever need to set a hint.
81
+ #
82
+ # @param [String, Array, OrderedHash] hint a single field, an array of
83
+ # fields, or a hash specifying fields
84
+ def hint=(hint=nil)
64
85
  @hint = normalize_hint_fields(hint)
65
86
  self
66
87
  end
@@ -70,7 +91,7 @@ module Mongo
70
91
  # The +selector+ argument is a prototype document that all results must
71
92
  # match. For example:
72
93
  #
73
- # collection.find({"hello" => "world"})
94
+ # collection.find({"hello" => "world"})
74
95
  #
75
96
  # only matches documents that have a key "hello" with value "world".
76
97
  # Matches can have other keys *in addition* to "hello".
@@ -80,51 +101,49 @@ module Mongo
80
101
  # evaluated cursors will be closed. If given no block +find+ returns a
81
102
  # cursor.
82
103
  #
83
- # :selector :: A document (hash) specifying elements which must be
84
- # present for a document to be included in the result set.
85
- #
86
- # Options:
87
- # :fields :: Array of field names that should be returned in the result
88
- # set ("_id" will always be included). By limiting results
89
- # to a certain subset of fields you can cut down on network
90
- # traffic and decoding time.
91
- # :skip :: Number of documents to omit (from the start of the result set)
92
- # when returning the results
93
- # :limit :: Maximum number of records to return
94
- # :sort :: An array of [key, direction] pairs to sort by. Direction should
95
- # be specified as Mongo::ASCENDING (or :ascending / :asc) or
96
- # Mongo::DESCENDING (or :descending / :desc)
97
- # :hint :: See #hint. This option overrides the collection-wide value.
98
- # :snapshot :: If true, snapshot mode will be used for this query.
99
- # Snapshot mode assures no duplicates are returned, or
100
- # objects missed, which were preset at both the start and
101
- # end of the query's execution. For details see
102
- # http://www.mongodb.org/display/DOCS/How+to+do+Snapshotting+in+the+Mongo+Database
103
- # :timeout :: When +true+ (default), the returned cursor will be subject to
104
- # the normal cursor timeout behavior of the mongod process.
105
- # When +false+, the returned cursor will never timeout. Note
106
- # that disabling timeout will only work when #find is invoked
107
- # with a block. This is to prevent any inadvertant failure to
108
- # close the cursor, as the cursor is explicitly closed when
109
- # block code finishes.
110
- def find(selector={}, options={})
111
- fields = options.delete(:fields)
104
+ # @param [Hash] selector
105
+ # a document specifying elements which must be present for a
106
+ # document to be included in the result set.
107
+ #
108
+ # @option opts [Array] :fields field names that should be returned in the result
109
+ # set ("_id" will always be included). By limiting results to a certain subset of fields,
110
+ # you can cut down on network traffic and decoding time.
111
+ # @option opts [Integer] :skip number of documents to skip from the beginning of the result set
112
+ # @option opts [Integer] :limit maximum number of documents to return
113
+ # @option opts [Array] :sort an array of [key, direction] pairs to sort by. Direction should
114
+ # be specified as Mongo::ASCENDING (or :ascending / :asc) or Mongo::DESCENDING (or :descending / :desc)
115
+ # @option opts [String, Array, OrderedHash] :hint hint for query optimizer, usually not necessary if using MongoDB > 1.1
116
+ # @option opts [Boolean] :snapshot ('false') if true, snapshot mode will be used for this query.
117
+ # Snapshot mode assures no duplicates are returned, or objects missed, which were preset at both the start and
118
+ # end of the query's execution. For details see http://www.mongodb.org/display/DOCS/How+to+do+Snapshotting+in+the+Mongo+Database
119
+ # @option opts [Boolean] :timeout ('true') when +true+, the returned cursor will be subject to
120
+ # the normal cursor timeout behavior of the mongod process. When +false+, the returned cursor will never timeout. Note
121
+ # that disabling timeout will only work when #find is invoked with a block. This is to prevent any inadvertant failure to
122
+ # close the cursor, as the cursor is explicitly closed when block code finishes.
123
+ #
124
+ # @raise [ArgumentError]
125
+ # if timeout is set to false and find is not invoked in a block
126
+ #
127
+ # @raise [RuntimeError]
128
+ # if given unknown options
129
+ def find(selector={}, opts={})
130
+ fields = opts.delete(:fields)
112
131
  fields = ["_id"] if fields && fields.empty?
113
- skip = options.delete(:skip) || skip || 0
114
- limit = options.delete(:limit) || 0
115
- sort = options.delete(:sort)
116
- hint = options.delete(:hint)
117
- snapshot = options.delete(:snapshot)
118
- if options[:timeout] == false && !block_given?
132
+ skip = opts.delete(:skip) || skip || 0
133
+ limit = opts.delete(:limit) || 0
134
+ sort = opts.delete(:sort)
135
+ hint = opts.delete(:hint)
136
+ snapshot = opts.delete(:snapshot)
137
+ if opts[:timeout] == false && !block_given?
119
138
  raise ArgumentError, "Timeout can be set to false only when #find is invoked with a block."
120
139
  end
121
- timeout = block_given? ? (options.delete(:timeout) || true) : true
140
+ timeout = block_given? ? (opts.delete(:timeout) || true) : true
122
141
  if hint
123
142
  hint = normalize_hint_fields(hint)
124
143
  else
125
144
  hint = @hint # assumed to be normalized already
126
145
  end
127
- raise RuntimeError, "Unknown options [#{options.inspect}]" unless options.empty?
146
+ raise RuntimeError, "Unknown options [#{opts.inspect}]" unless opts.empty?
128
147
 
129
148
  cursor = Cursor.new(self, :selector => selector, :fields => fields, :skip => skip, :limit => limit,
130
149
  :order => sort, :hint => hint, :snapshot => snapshot, :timeout => timeout)
@@ -137,17 +156,22 @@ module Mongo
137
156
  end
138
157
  end
139
158
 
140
- # Get a single object from the database.
159
+ # Return a single object from the database.
141
160
  #
142
- # Raises TypeError if the argument is of an improper type. Returns a
143
- # single document (hash), or nil if no result is found.
161
+ # @return [OrderedHash, Nil]
162
+ # a single document or nil if no result is found.
144
163
  #
145
- # :spec_or_object_id :: a hash specifying elements which must be
146
- # present for a document to be included in the result set OR an
164
+ # @param [Hash, ObjectID, Nil] spec_or_object_id a hash specifying elements
165
+ # which must be present for a document to be included in the result set or an
147
166
  # instance of ObjectID to be used as the value for an _id query.
148
- # if nil an empty spec, {}, will be used.
149
- # :options :: options, as passed to Collection#find
150
- def find_one(spec_or_object_id=nil, options={})
167
+ # If nil, an empty selector, {}, will be used.
168
+ #
169
+ # @option opts [Hash]
170
+ # any valid options that can be send to Collection#find
171
+ #
172
+ # @raise [TypeError]
173
+ # if the argument is of an improper type.
174
+ def find_one(spec_or_object_id=nil, opts={})
151
175
  spec = case spec_or_object_id
152
176
  when nil
153
177
  {}
@@ -158,45 +182,45 @@ module Mongo
158
182
  else
159
183
  raise TypeError, "spec_or_object_id must be an instance of ObjectID or Hash, or nil"
160
184
  end
161
- find(spec, options.merge(:limit => -1)).next_document
185
+ find(spec, opts.merge(:limit => -1)).next_document
162
186
  end
163
187
 
164
- # Save a document in this collection.
188
+ # Save a document to this collection.
165
189
  #
166
- # If +to_save+ already has an '_id' then an update (upsert) operation
167
- # is performed and any existing document with that _id is overwritten.
168
- # Otherwise an insert operation is performed. Returns the _id of the
169
- # saved document.
190
+ # @param [Hash] doc
191
+ # the document to be saved. If the document already has an '_id' key,
192
+ # then an update (upsert) operation will be performed, and any existing
193
+ # document with that _id is overwritten. Otherwise an insert operation is performed.
170
194
  #
171
- # :to_save :: the document (a hash) to be saved
195
+ # @return [ObjectID] the _id of the saved document.
172
196
  #
173
- # Options:
174
- # :safe :: if true, check that the save succeeded. OperationFailure
175
- # will be raised on an error. Checking for safety requires an extra
176
- # round-trip to the database
177
- def save(to_save, options={})
178
- if to_save.has_key?(:_id) || to_save.has_key?('_id')
179
- id = to_save[:_id] || to_save['_id']
180
- update({:_id => id}, to_save, :upsert => true, :safe => options.delete(:safe))
197
+ # @option opts [Boolean] :safe (+false+)
198
+ # If true, check that the save succeeded. OperationFailure
199
+ # will be raised on an error. Note that a safe check requires an extra
200
+ # round-trip to the database.
201
+ def save(doc, options={})
202
+ if doc.has_key?(:_id) || doc.has_key?('_id')
203
+ id = doc[:_id] || doc['_id']
204
+ update({:_id => id}, doc, :upsert => true, :safe => options.delete(:safe))
181
205
  id
182
206
  else
183
- insert(to_save, :safe => options.delete(:safe))
207
+ insert(doc, :safe => options.delete(:safe))
184
208
  end
185
209
  end
186
210
 
187
- # Insert a document(s) into this collection.
211
+ # Insert one or more documents into the collection.
188
212
  #
189
- # "<<" is aliased to this method. Returns the _id of the inserted
190
- # document or a list of _ids of the inserted documents. The object(s)
191
- # may have been modified by the database's PK factory, if it has one.
213
+ # @param [Hash, Array] doc_or_docs
214
+ # a document (as a hash) or array of documents to be inserted.
192
215
  #
193
- # :doc_or_docs :: a document (as a hash) or Array of documents to be
194
- # inserted
216
+ # @return [ObjectID, Array]
217
+ # the _id of the inserted document or a list of _ids of all inserted documents.
218
+ # Note: the object may have been modified by the database's PK factory, if it has one.
195
219
  #
196
- # Options:
197
- # :safe :: if true, check that the insert succeeded. OperationFailure
198
- # will be raised on an error. Checking for safety requires an extra
199
- # round-trip to the database
220
+ # @option opts [Boolean] :safe (+false+)
221
+ # If true, check that the save succeeded. OperationFailure
222
+ # will be raised on an error. Note that a safe check requires an extra
223
+ # round-trip to the database.
200
224
  def insert(doc_or_docs, options={})
201
225
  doc_or_docs = [doc_or_docs] unless doc_or_docs.is_a?(Array)
202
226
  doc_or_docs.collect! { |doc| @pk_factory.create_pk(doc) }
@@ -205,52 +229,72 @@ module Mongo
205
229
  end
206
230
  alias_method :<<, :insert
207
231
 
208
- # Remove all records from this collection.
209
- # If +selector+ is specified, only matching documents will be removed.
232
+ # Remove all documents from this collection.
210
233
  #
211
- # Remove all records from the collection:
212
- # @collection.remove
213
- # @collection.remove({})
234
+ # @param [Hash] selector
235
+ # If specified, only matching documents will be removed.
214
236
  #
215
- # Remove only records that have expired:
216
- # @collection.remove({:expire => {'$lte' => Time.now}})
217
- def remove(selector={})
218
- message = ByteBuffer.new
219
- message.put_int(0)
237
+ # @option opts [Boolean] :safe [false] run the operation in safe mode, which
238
+ # will call :getlasterror on the database and report any assertions.
239
+ #
240
+ # @example remove all documents from the 'users' collection:
241
+ # users.remove
242
+ # users.remove({})
243
+ #
244
+ # @example remove only documents that have expired:
245
+ # users.remove({:expire => {"$lte" => Time.now}})
246
+ #
247
+ # @return [True]
248
+ #
249
+ # @raise [Mongo::OperationFailure] an exception will be raised iff safe mode is enabled
250
+ # and the operation fails.
251
+ def remove(selector={}, opts={})
252
+ # Initial byte is 0.
253
+ message = ByteBuffer.new([0, 0, 0, 0])
220
254
  BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{@name}")
221
255
  message.put_int(0)
222
- message.put_array(BSON.serialize(selector, false).unpack("C*"))
223
- @connection.send_message(Mongo::Constants::OP_DELETE, message,
224
- "db.#{@db.name}.remove(#{selector.inspect})")
256
+ message.put_array(BSON.serialize(selector, false).to_a)
257
+
258
+ if opts[:safe]
259
+ @connection.send_message_with_safe_check(Mongo::Constants::OP_DELETE, message,
260
+ "db.#{@db.name}.remove(#{selector.inspect})")
261
+ # the return value of send_message_with_safe_check isn't actually meaningful --
262
+ # only the fact that it didn't raise an error is -- so just return true
263
+ true
264
+ else
265
+ @connection.send_message(Mongo::Constants::OP_DELETE, message,
266
+ "db.#{@db.name}.remove(#{selector.inspect})")
267
+ end
225
268
  end
226
269
 
227
270
  # Update a single document in this collection.
228
271
  #
229
- # :selector :: a hash specifying elements which must be present for a document to be updated. Note:
230
- # the update command currently updates only the first document matching the
231
- # given selector. If you want all matching documents to be updated, be sure
232
- # to specify :multi => true.
233
- # :document :: a hash specifying the fields to be changed in the
234
- # selected document, or (in the case of an upsert) the document to
235
- # be inserted
236
- #
237
- # Options:
238
- # :upsert :: if true, perform an upsert operation
239
- # :multi :: update all documents matching the selector, as opposed to
240
- # just the first matching document. Note: only works in 1.1.3 or later.
241
- # :safe :: if true, check that the update succeeded. OperationFailure
242
- # will be raised on an error. Checking for safety requires an extra
243
- # round-trip to the database
272
+ # @param [Hash] selector
273
+ # a hash specifying elements which must be present for a document to be updated. Note:
274
+ # the update command currently updates only the first document matching the
275
+ # given selector. If you want all matching documents to be updated, be sure
276
+ # to specify :multi => true.
277
+ # @param [Hash] document
278
+ # a hash specifying the fields to be changed in the selected document,
279
+ # or (in the case of an upsert) the document to be inserted
280
+ #
281
+ # @option [Boolean] :upsert (+false+) if true, performs an upsert (update or insert)
282
+ # @option [Boolean] :multi (+false+) update all documents matching the selector, as opposed to
283
+ # just the first matching document. Note: only works in MongoDB 1.1.3 or later.
284
+ # @option opts [Boolean] :safe (+false+)
285
+ # If true, check that the save succeeded. OperationFailure
286
+ # will be raised on an error. Note that a safe check requires an extra
287
+ # round-trip to the database.
244
288
  def update(selector, document, options={})
245
- message = ByteBuffer.new
246
- message.put_int(0)
289
+ # Initial byte is 0.
290
+ message = ByteBuffer.new([0, 0, 0, 0])
247
291
  BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{@name}")
248
292
  update_options = 0
249
293
  update_options += 1 if options[:upsert]
250
294
  update_options += 2 if options[:multi]
251
295
  message.put_int(update_options)
252
- message.put_array(BSON.serialize(selector, false).unpack("C*"))
253
- message.put_array(BSON.serialize(document, false).unpack("C*"))
296
+ message.put_array(BSON.serialize(selector, false).to_a)
297
+ message.put_array(BSON.serialize(document, false).to_a)
254
298
  if options[:safe]
255
299
  @connection.send_message_with_safe_check(Mongo::Constants::OP_UPDATE, message, @db.name,
256
300
  "db.#{@name}.update(#{selector.inspect}, #{document.inspect})")
@@ -260,12 +304,15 @@ module Mongo
260
304
  end
261
305
  end
262
306
 
263
- # Create a new index. +field_or_spec+
264
- # should be either a single field name or a Array of [field name,
265
- # direction] pairs. Directions should be specified as
266
- # Mongo::ASCENDING or Mongo::DESCENDING.
267
- # +unique+ is an optional boolean indicating whether this index
268
- # should enforce a uniqueness constraint.
307
+ # Create a new index.
308
+ #
309
+ # @param [String, Array] field_or_spec
310
+ # should be either a single field name or an array of
311
+ # [field name, direction] pairs. Directions should be specified as Mongo::ASCENDING or Mongo::DESCENDING.
312
+ #
313
+ # @param [Boolean] unique if true, this index will enforce a uniqueness constraint.
314
+ #
315
+ # @return [String] the name of the index created.
269
316
  def create_index(field_or_spec, unique=false)
270
317
  field_h = OrderedHash.new
271
318
  if field_or_spec.is_a?(String) || field_or_spec.is_a?(Symbol)
@@ -283,15 +330,19 @@ module Mongo
283
330
  name
284
331
  end
285
332
 
286
- # Drop index +name+.
333
+ # Drop a specified index.
334
+ #
335
+ # @param [String] name
287
336
  def drop_index(name)
288
337
  @db.drop_index(@name, name)
289
338
  end
290
339
 
291
340
  # Drop all indexes.
292
341
  def drop_indexes
293
- # just need to call drop indexes with no args; will drop them all
342
+
343
+ # Note: calling drop_indexes with no args will drop them all.
294
344
  @db.drop_index(@name, '*')
345
+
295
346
  end
296
347
 
297
348
  # Drop the entire collection. USE WITH CAUTION.
@@ -299,26 +350,26 @@ module Mongo
299
350
  @db.drop_collection(@name)
300
351
  end
301
352
 
302
- # Performs a map/reduce operation on the current collection. Returns a new
303
- # collection containing the results of the operation.
304
- #
305
- # Required:
306
- # +map+ :: a map function, written in javascript.
307
- # +reduce+ :: a reduce function, written in javascript.
308
- #
309
- # Optional:
310
- # :query :: a query selector document, like what's passed to #find, to limit
311
- # the operation to a subset of the collection.
312
- # :sort :: sort parameters passed to the query.
313
- # :limit :: number of objects to return from the collection.
314
- # :finalize :: a javascript function to apply to the result set after the
315
- # map/reduce operation has finished.
316
- # :out :: the name of the output collection. if specified, the collection will not be treated as temporary.
317
- # :keeptemp :: if true, the generated collection will be persisted. default is false.
318
- # :verbose :: if true, provides statistics on job execution time.
319
- #
320
- # For more information on using map/reduce, see http://www.mongodb.org/display/DOCS/MapReduce
321
- def map_reduce(map, reduce, options={})
353
+ # Perform a map/reduce operation on the current collection.
354
+ #
355
+ # @param [String, Code] map a map function, written in JavaScript.
356
+ # @param [String, Code] reduce a reduce function, written in JavaScript.
357
+ #
358
+ # @option opts [Hash] :query ({}) a query selector document, like what's passed to #find, to limit
359
+ # the operation to a subset of the collection.
360
+ # @option opts [Array] :sort ([]) an array of [key, direction] pairs to sort by. Direction should
361
+ # be specified as Mongo::ASCENDING (or :ascending / :asc) or Mongo::DESCENDING (or :descending / :desc)
362
+ # @option opts [Integer] :limit (nil) if passing a query, number of objects to return from the collection.
363
+ # @option opts [String, Code] :finalize (nil) a javascript function to apply to the result set after the
364
+ # map/reduce operation has finished.
365
+ # @option opts [String] :out (nil) the name of the output collection. If specified, the collection will not be treated as temporary.
366
+ # @option opts [Boolean] :keeptemp (false) if true, the generated collection will be persisted. default is false.
367
+ # @option opts [Boolean ] :verbose (false) if true, provides statistics on job execution time.
368
+ #
369
+ # @return [Collection] a collection containing the results of the operation.
370
+ #
371
+ # @see http://www.mongodb.org/display/DOCS/MapReduce Offical MongoDB map/reduce documentation.
372
+ def map_reduce(map, reduce, opts={})
322
373
  map = Code.new(map) unless map.is_a?(Code)
323
374
  reduce = Code.new(reduce) unless reduce.is_a?(Code)
324
375
 
@@ -326,7 +377,7 @@ module Mongo
326
377
  hash['mapreduce'] = self.name
327
378
  hash['map'] = map
328
379
  hash['reduce'] = reduce
329
- hash.merge! options
380
+ hash.merge! opts
330
381
 
331
382
  result = @db.command(hash)
332
383
  unless result["ok"] == 1
@@ -336,20 +387,20 @@ module Mongo
336
387
  end
337
388
  alias :mapreduce :map_reduce
338
389
 
339
- # Performs a group query, similar to the 'SQL GROUP BY' operation.
340
- # Returns an array of grouped items.
390
+ # Perform a group aggregation.
341
391
  #
342
- # :key :: either 1) an array of fields to group by, 2) a javascript function to generate
343
- # the key object, or 3) nil.
344
- # :condition :: an optional document specifying a query to limit the documents over which group is run.
345
- # :initial :: initial value of the aggregation counter object
346
- # :reduce :: aggregation function as a JavaScript string
347
- # :finalize :: optional. a JavaScript function that receives and modifies
392
+ # @param [Array, String, Code, Nil] :key either 1) an array of fields to group by,
393
+ # 2) a javascript function to generate the key object, or 3) nil.
394
+ # @param [Hash] condition an optional document specifying a query to limit the documents over which group is run.
395
+ # @param [Hash] initial initial value of the aggregation counter object
396
+ # @param [String, Code] reduce aggregation function, in JavaScript
397
+ # @param [String, Code] finalize :: optional. a JavaScript function that receives and modifies
348
398
  # each of the resultant grouped objects. Available only when group is run
349
399
  # with command set to true.
350
- # :command :: if true, run the group as a command instead of in an
351
- # eval - it is likely that this option will eventually be
352
- # deprecated and all groups will be run as commands
400
+ # @param [Boolean] command if true, run the group as a command instead of in an
401
+ # eval. Note: Running group as eval has been DEPRECATED.
402
+ #
403
+ # @return [Array] the grouped items.
353
404
  def group(key, condition, initial, reduce, command=false, finalize=nil)
354
405
 
355
406
  if command
@@ -443,9 +494,14 @@ EOS
443
494
  end
444
495
  end
445
496
 
446
- # Returns a list of distinct values for +key+ across all
497
+ # Return a list of distinct values for +key+ across all
447
498
  # documents in the collection. The key may use dot notation
448
499
  # to reach into an embedded object.
500
+ #
501
+ # @param [String, Symbol, OrderedHash] key or hash to group by.
502
+ # @param [Hash] query a selector for limiting the result set over which to group.
503
+ #
504
+ # @example Saving zip codes and ages and returning distinct results.
449
505
  # @collection.save({:zip => 10010, :name => {:age => 27}})
450
506
  # @collection.save({:zip => 94108, :name => {:age => 24}})
451
507
  # @collection.save({:zip => 10010, :name => {:age => 27}})
@@ -457,10 +513,12 @@ EOS
457
513
  # @collection.distinct("name.age")
458
514
  # [27, 24]
459
515
  #
460
- # You may also pass a document selector as the second parameter
461
- # to limit the documents over which distinct is run:
516
+ # # You may also pass a document selector as the second parameter
517
+ # # to limit the documents over which distinct is run:
462
518
  # @collection.distinct("name.age", {"name.age" => {"$gt" => 24}})
463
519
  # [27]
520
+ #
521
+ # @return [Array] an array of distinct values.
464
522
  def distinct(key, query=nil)
465
523
  raise MongoArgumentError unless [String, Symbol].include?(key.class)
466
524
  command = OrderedHash.new
@@ -473,11 +531,12 @@ EOS
473
531
 
474
532
  # Rename this collection.
475
533
  #
476
- # If operating in auth mode, client must be authorized as an admin to
477
- # perform this operation. Raises +InvalidName+ if +new_name+ is an invalid
478
- # collection name.
534
+ # Note: If operating in auth mode, the client must be authorized as an admin to
535
+ # perform this operation.
536
+ #
537
+ # @param [String ] new_name the new name for this collection
479
538
  #
480
- # :new_name :: new name for this collection
539
+ # @raise [InvalidName] if +new_name+ is an invalid collection name.
481
540
  def rename(new_name)
482
541
  case new_name
483
542
  when Symbol, String
@@ -500,23 +559,25 @@ EOS
500
559
  @db.rename_collection(@name, new_name)
501
560
  end
502
561
 
503
- # Get information on the indexes for the collection +collection_name+.
504
- # Returns a hash where the keys are index names (as returned by
505
- # Collection#create_index and the values are lists of [key, direction]
506
- # pairs specifying the index (as passed to Collection#create_index).
562
+ # Get information on the indexes for this collection.
563
+ #
564
+ # @return [Hash] a hash where the keys are index names.
507
565
  def index_information
508
566
  @db.index_information(@name)
509
567
  end
510
568
 
511
569
  # Return a hash containing options that apply to this collection.
512
- # 'create' will be the collection name. For the other possible keys
513
- # and values, see DB#create_collection.
570
+ # For all possible keys and values, see DB#create_collection.
571
+ #
572
+ # @return [Hash] options that apply to this collection.
514
573
  def options
515
574
  @db.collections_info(@name).next_document['options']
516
575
  end
517
576
 
518
577
  # Get the number of documents in this collection.
519
- def count()
578
+ #
579
+ # @return [Integer]
580
+ def count
520
581
  find().count()
521
582
  end
522
583
 
@@ -545,10 +606,10 @@ EOS
545
606
  # Takes an array of +documents+, an optional +collection_name+, and a
546
607
  # +check_keys+ setting.
547
608
  def insert_documents(documents, collection_name=@name, check_keys=true, safe=false)
548
- message = ByteBuffer.new
549
- message.put_int(0)
609
+ # Initial byte is 0.
610
+ message = ByteBuffer.new([0, 0, 0, 0])
550
611
  BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{collection_name}")
551
- documents.each { |doc| message.put_array(BSON.serialize(doc, check_keys).unpack("C*")) }
612
+ documents.each { |doc| message.put_array(BSON.serialize(doc, check_keys).to_a) }
552
613
  if safe
553
614
  @connection.send_message_with_safe_check(Mongo::Constants::OP_INSERT, message, @db.name,
554
615
  "db.#{collection_name}.insert(#{documents.inspect})")