mongo 0.18.2 → 0.18.3

Sign up to get free protection for your applications and to get access to all the features.
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})")