mongo 0.18.1 → 0.18.2

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.
data/README.rdoc CHANGED
@@ -13,7 +13,7 @@ Here is a quick code sample. See the MongoDB Ruby Tutorial
13
13
  @coll = db.collection('test')
14
14
 
15
15
  @coll.remove
16
- 3.times do |i|
16
+ 3.times do |i|
17
17
  @coll.insert({'a' => i+1})
18
18
  end
19
19
  puts "There are #{@coll.count()} records. Here they are:"
@@ -254,7 +254,7 @@ Random cursor fun facts:
254
254
 
255
255
  = Testing
256
256
 
257
- If you have the source code, you can run the tests. There's a separate rake task for testing with
257
+ If you have the source code, you can run the tests. There's a separate rake task for testing with
258
258
  the mongo_ext c extension enabled.
259
259
 
260
260
  $ rake test:c
@@ -329,63 +329,7 @@ See HISTORY.
329
329
 
330
330
  = Credits
331
331
 
332
- Adrian Madrid, aemadrid@gmail.com
333
- * bin/mongo_console
334
- * examples/benchmarks.rb
335
- * examples/irb.rb
336
- * Modifications to examples/simple.rb
337
- * Found plenty of bugs and missing features.
338
- * Ruby 1.9 support.
339
- * Gem support.
340
- * Many other code suggestions and improvements.
341
-
342
- Aman Gupta, aman@tmm1.net
343
- * Collection#save
344
-
345
- Jon Crosby, jon@joncrosby.me
346
- * Some code clean-up
347
-
348
- John Nunemaker, http://railstips.org
349
- * Collection#create_index takes symbols as well as strings
350
- * Fix for Collection#save
351
- * Add logger convenience methods to connection and database
352
-
353
- David James, djames@sunlightfoundation.com
354
- * Fix dates to return as UTC
355
-
356
- Paul Dlug, paul.dlug@gmail.com
357
- * Generate _id on the client side if not provided
358
- * Collection#insert and Collection#save return _id
359
-
360
- Durran Jordan, durran@gmail.com
361
- * DB#collections
362
- * Support for specifying sort order as array of [key, direction] pairs
363
-
364
- Cyril Mougel, cyril.mougel@gmail.com
365
- * Initial logging support
366
- * Test case
367
-
368
- Jack Chen, chendo on github
369
- * Test case + fix for deserializing pre-epoch Time instances
370
-
371
- Michael Bernstein, mrb on github
372
- * #sort method for Cursor instances
373
-
374
- Paulo Ahahgon, pahagon on github
375
- * removed hard limit
376
-
377
- Les Hill, leshill on github
378
- * OrderedHash#each returns self
379
-
380
- Sean Cribbs, seancribbs on github
381
- * Modify standard_benchmark to allow profiling
382
-
383
- Sunny Hirai
384
- * Suggested hashcode fix for Mongo::ObjectID
385
- * Noted index ordering bug.
386
-
387
- Christos Trochalakis
388
- * Added map/reduce helper
332
+ See CREDITS.
389
333
 
390
334
  = License
391
335
 
data/Rakefile CHANGED
@@ -1,3 +1,4 @@
1
+ # -*- mode: ruby; -*-
1
2
  require 'rubygems'
2
3
  require 'rubygems/specification'
3
4
  require 'fileutils'
@@ -12,9 +13,6 @@ require 'rbconfig'
12
13
  include Config
13
14
  ENV['TEST_MODE'] = 'TRUE'
14
15
 
15
- gem_command = "gem"
16
- gem_command = "gem1.9" if $0.match(/1\.9$/) # use gem1.9 if we used rake1.9
17
-
18
16
  desc "Test the MongoDB Ruby driver."
19
17
  task :test do
20
18
  puts "\nThis option has changed."
@@ -95,20 +93,16 @@ namespace :gem do
95
93
 
96
94
  desc "Install the gem locally"
97
95
  task :install do
98
- sh <<EOS
99
- #{gem_command} build mongo-ruby-driver.gemspec &&
100
- #{gem_command} install mongo-*.gem &&
101
- rm mongo-*.gem
102
- EOS
96
+ sh "gem build mongo-ruby-driver.gemspec"
97
+ sh "gem install mongo-*.gem"
98
+ sh "rm mongo-*.gem"
103
99
  end
104
100
 
105
101
  desc "Install the optional c extensions"
106
102
  task :install_extensions do
107
- sh <<EOS
108
- #{gem_command} build mongo-extensions.gemspec &&
109
- #{gem_command} install mongo_ext-*.gem &&
110
- rm mongo_ext-*.gem
111
- EOS
103
+ sh "gem build mongo-extensions.gemspec"
104
+ sh "gem install mongo_ext-*.gem"
105
+ sh "rm mongo_ext-*.gem"
112
106
  end
113
107
 
114
108
  end
data/bin/perf.rb ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'mongo'
4
+ require 'benchmark'
5
+ require 'socket'
6
+ require 'digest/md5'
7
+ require 'thread'
8
+
9
+ include Mongo
10
+
11
+ c = Mongo::Connection.new('localhost', 27017, :pool_size => 10)
12
+ coll = c['perf']['docs']
13
+ coll.remove
14
+
15
+ doc = {'name' => 'kyle',
16
+ 'languages' => ['ruby', 'javascript', 'c'],
17
+ 'date' => Time.now}
18
+
19
+ TRIES = 5000
20
+ @threads = []
21
+ 100.times do |n|
22
+ @threads << Thread.new do
23
+ 50.times do |n|
24
+ doc['n'] = n*n
25
+ coll.insert(doc)
26
+ doc.delete(:_id)
27
+ end
28
+ end
29
+ end
30
+ @threads.join
data/examples/cursor.rb CHANGED
@@ -33,14 +33,14 @@ array = cursor.to_a
33
33
  cursor.each { |row| pp row }
34
34
 
35
35
  # You can get the next object
36
- first_object = coll.find().next_object
36
+ first_object = coll.find().next_document
37
37
 
38
- # next_object returns nil if there are no more objects that match
38
+ # next_document returns nil if there are no more objects that match
39
39
  cursor = coll.find()
40
- obj = cursor.next_object
40
+ obj = cursor.next_document
41
41
  while obj
42
42
  pp obj
43
- obj = cursor.next_object
43
+ obj = cursor.next_document
44
44
  end
45
45
 
46
46
  # Destroy the collection
data/examples/types.rb CHANGED
@@ -30,6 +30,6 @@ coll.insert('array' => [1, 2, 3],
30
30
  'null' => nil,
31
31
  'symbol' => :zildjian)
32
32
 
33
- pp coll.find().next_object
33
+ pp coll.find().next_document
34
34
 
35
35
  coll.clear
data/lib/mongo.rb CHANGED
@@ -4,7 +4,7 @@ module Mongo
4
4
  ASCENDING = 1
5
5
  DESCENDING = -1
6
6
 
7
- VERSION = "0.18.1"
7
+ VERSION = "0.18.2"
8
8
  end
9
9
 
10
10
  begin
@@ -21,7 +21,7 @@ begin
21
21
  warn " You can install the extension as follows:\n gem install mongo_ext\n"
22
22
  warn " If you continue to receive this message after installing, make sure that the"
23
23
  warn " mongo_ext gem is in your load path and that the mongo_ext and mongo gems are of the same version.\n"
24
- end
24
+ end
25
25
 
26
26
  require 'mongo/types/binary'
27
27
  require 'mongo/types/code'
data/lib/mongo/admin.rb CHANGED
@@ -59,8 +59,7 @@ module Mongo
59
59
  raise "Error with profile command: #{doc.inspect}" unless @db.ok?(doc)
60
60
  end
61
61
 
62
- # Return an array contining current profiling information from the
63
- # database.
62
+ # Returns an array containing current profiling information.
64
63
  def profiling_info
65
64
  Cursor.new(Collection.new(@db, DB::SYSTEM_PROFILE_COLLECTION), :selector => {}).to_a
66
65
  end
@@ -100,12 +100,12 @@ module Mongo
100
100
  # objects missed, which were preset at both the start and
101
101
  # end of the query's execution. For details see
102
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.
103
+ # :timeout :: When +true+ (default), the returned cursor will be subject to
104
+ # the normal cursor timeout behavior of the mongod process.
105
105
  # When +false+, the returned cursor will never timeout. Note
106
106
  # that disabling timeout will only work when #find is invoked
107
107
  # with a block. This is to prevent any inadvertant failure to
108
- # close the cursor, as the cursor is explicitly closed when
108
+ # close the cursor, as the cursor is explicitly closed when
109
109
  # block code finishes.
110
110
  def find(selector={}, options={})
111
111
  fields = options.delete(:fields)
@@ -116,7 +116,7 @@ module Mongo
116
116
  hint = options.delete(:hint)
117
117
  snapshot = options.delete(:snapshot)
118
118
  if options[:timeout] == false && !block_given?
119
- raise ArgumentError, "Timeout can be set to false only when #find is invoked with a block."
119
+ raise ArgumentError, "Timeout can be set to false only when #find is invoked with a block."
120
120
  end
121
121
  timeout = block_given? ? (options.delete(:timeout) || true) : true
122
122
  if hint
@@ -126,7 +126,7 @@ module Mongo
126
126
  end
127
127
  raise RuntimeError, "Unknown options [#{options.inspect}]" unless options.empty?
128
128
 
129
- cursor = Cursor.new(self, :selector => selector, :fields => fields, :skip => skip, :limit => limit,
129
+ cursor = Cursor.new(self, :selector => selector, :fields => fields, :skip => skip, :limit => limit,
130
130
  :order => sort, :hint => hint, :snapshot => snapshot, :timeout => timeout)
131
131
  if block_given?
132
132
  yield cursor
@@ -158,7 +158,7 @@ module Mongo
158
158
  else
159
159
  raise TypeError, "spec_or_object_id must be an instance of ObjectID or Hash, or nil"
160
160
  end
161
- find(spec, options.merge(:limit => -1)).next_object
161
+ find(spec, options.merge(:limit => -1)).next_document
162
162
  end
163
163
 
164
164
  # Save a document in this collection.
@@ -175,7 +175,8 @@ module Mongo
175
175
  # will be raised on an error. Checking for safety requires an extra
176
176
  # round-trip to the database
177
177
  def save(to_save, options={})
178
- if id = to_save[:_id] || to_save['_id']
178
+ if to_save.has_key?(:_id) || to_save.has_key?('_id')
179
+ id = to_save[:_id] || to_save['_id']
179
180
  update({:_id => id}, to_save, :upsert => true, :safe => options.delete(:safe))
180
181
  id
181
182
  else
@@ -204,14 +205,14 @@ module Mongo
204
205
  end
205
206
  alias_method :<<, :insert
206
207
 
207
- # Remove all records from this collection.
208
+ # Remove all records from this collection.
208
209
  # If +selector+ is specified, only matching documents will be removed.
209
- #
210
+ #
210
211
  # Remove all records from the collection:
211
212
  # @collection.remove
212
213
  # @collection.remove({})
213
214
  #
214
- # Remove only records that have expired:
215
+ # Remove only records that have expired:
215
216
  # @collection.remove({:expire => {'$lte' => Time.now}})
216
217
  def remove(selector={})
217
218
  message = ByteBuffer.new
@@ -225,7 +226,7 @@ module Mongo
225
226
 
226
227
  # Update a single document in this collection.
227
228
  #
228
- # :selector :: a hash specifying elements which must be present for a document to be updated. Note:
229
+ # :selector :: a hash specifying elements which must be present for a document to be updated. Note:
229
230
  # the update command currently updates only the first document matching the
230
231
  # given selector. If you want all matching documents to be updated, be sure
231
232
  # to specify :multi => true.
@@ -254,7 +255,7 @@ module Mongo
254
255
  @connection.send_message_with_safe_check(Mongo::Constants::OP_UPDATE, message, @db.name,
255
256
  "db.#{@name}.update(#{selector.inspect}, #{document.inspect})")
256
257
  else
257
- @connection.send_message(Mongo::Constants::OP_UPDATE, message,
258
+ @connection.send_message(Mongo::Constants::OP_UPDATE, message,
258
259
  "db.#{@name}.update(#{selector.inspect}, #{document.inspect})")
259
260
  end
260
261
  end
@@ -329,7 +330,7 @@ module Mongo
329
330
 
330
331
  result = @db.command(hash)
331
332
  unless result["ok"] == 1
332
- raise Mongo::OperationFailure, "map-reduce failed: #{result['errmsg']}"
333
+ raise Mongo::OperationFailure, "map-reduce failed: #{result['errmsg']}"
333
334
  end
334
335
  @db[result["result"]]
335
336
  end
@@ -338,48 +339,80 @@ module Mongo
338
339
  # Performs a group query, similar to the 'SQL GROUP BY' operation.
339
340
  # Returns an array of grouped items.
340
341
  #
341
- # :keys :: Array of fields to group by
342
- # :condition :: specification of rows to be considered (as a 'find'
343
- # query specification)
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.
344
345
  # :initial :: initial value of the aggregation counter object
345
346
  # :reduce :: aggregation function as a JavaScript string
347
+ # :finalize :: optional. a JavaScript function that receives and modifies
348
+ # each of the resultant grouped objects. Available only when group is run
349
+ # with command set to true.
346
350
  # :command :: if true, run the group as a command instead of in an
347
351
  # eval - it is likely that this option will eventually be
348
352
  # deprecated and all groups will be run as commands
349
- def group(keys, condition, initial, reduce, command=false)
353
+ def group(key, condition, initial, reduce, command=false, finalize=nil)
354
+
350
355
  if command
351
- hash = {}
352
- keys.each do |k|
353
- hash[k] = 1
354
- end
355
356
 
356
357
  reduce = Code.new(reduce) unless reduce.is_a?(Code)
357
358
 
358
- result = @db.command({"group" =>
359
- {
360
- "ns" => @name,
361
- "$reduce" => reduce,
362
- "key" => hash,
363
- "cond" => condition,
364
- "initial" => initial}})
359
+ group_command = {
360
+ "group" => {
361
+ "ns" => @name,
362
+ "$reduce" => reduce,
363
+ "cond" => condition,
364
+ "initial" => initial
365
+ }
366
+ }
367
+
368
+ unless key.nil?
369
+ if key.is_a? Array
370
+ key_type = "key"
371
+ key_value = {}
372
+ key.each { |k| key_value[k] = 1 }
373
+ else
374
+ key_type = "$keyf"
375
+ key_value = key.is_a?(Code) ? key : Code.new(key)
376
+ end
377
+
378
+ group_command["group"][key_type] = key_value
379
+ end
380
+
381
+ # only add finalize if specified
382
+ if finalize
383
+ finalize = Code.new(finalize) unless finalize.is_a?(Code)
384
+ group_command['group']['finalize'] = finalize
385
+ end
386
+
387
+ result = @db.command group_command
388
+
365
389
  if result["ok"] == 1
366
390
  return result["retval"]
367
391
  else
368
392
  raise OperationFailure, "group command failed: #{result['errmsg']}"
369
393
  end
370
- end
371
394
 
372
- case reduce
373
- when Code
374
- scope = reduce.scope
375
395
  else
376
- scope = {}
377
- end
378
- scope.merge!({
379
- "ns" => @name,
380
- "keys" => keys,
381
- "condition" => condition,
382
- "initial" => initial })
396
+
397
+ warn "Collection#group must now be run as a command; you can do this by passing 'true' as the command argument."
398
+
399
+ raise OperationFailure, ":finalize can be specified only when " +
400
+ "group is run as a command (set command param to true)" if finalize
401
+
402
+ raise OperationFailure, "key must be an array of fields to group by. If you want to pass a key function,
403
+ run group as a command by passing 'true' as the command argument." unless key.is_a? Array || key.nil?
404
+
405
+ case reduce
406
+ when Code
407
+ scope = reduce.scope
408
+ else
409
+ scope = {}
410
+ end
411
+ scope.merge!({
412
+ "ns" => @name,
413
+ "keys" => key,
414
+ "condition" => condition,
415
+ "initial" => initial })
383
416
 
384
417
  group_function = <<EOS
385
418
  function () {
@@ -406,7 +439,8 @@ function () {
406
439
  return {"result": map.values()};
407
440
  }
408
441
  EOS
409
- @db.eval(Code.new(group_function, scope))["result"]
442
+ @db.eval(Code.new(group_function, scope))["result"]
443
+ end
410
444
  end
411
445
 
412
446
  # Returns a list of distinct values for +key+ across all
@@ -422,11 +456,17 @@ EOS
422
456
  # [10010, 94108, 99701]
423
457
  # @collection.distinct("name.age")
424
458
  # [27, 24]
425
- def distinct(key)
459
+ #
460
+ # You may also pass a document selector as the second parameter
461
+ # to limit the documents over which distinct is run:
462
+ # @collection.distinct("name.age", {"name.age" => {"$gt" => 24}})
463
+ # [27]
464
+ def distinct(key, query=nil)
426
465
  raise MongoArgumentError unless [String, Symbol].include?(key.class)
427
466
  command = OrderedHash.new
428
467
  command[:distinct] = @name
429
- command[:key] = key.to_s
468
+ command[:key] = key.to_s
469
+ command[:query] = query
430
470
 
431
471
  @db.command(command)["values"]
432
472
  end
@@ -472,7 +512,7 @@ EOS
472
512
  # 'create' will be the collection name. For the other possible keys
473
513
  # and values, see DB#create_collection.
474
514
  def options
475
- @db.collections_info(@name).next_object()['options']
515
+ @db.collections_info(@name).next_document['options']
476
516
  end
477
517
 
478
518
  # Get the number of documents in this collection.
@@ -501,7 +541,7 @@ EOS
501
541
 
502
542
  private
503
543
 
504
- # Sends an Mongo::Constants::OP_INSERT message to the database.
544
+ # Sends a Mongo::Constants::OP_INSERT message to the database.
505
545
  # Takes an array of +documents+, an optional +collection_name+, and a
506
546
  # +check_keys+ setting.
507
547
  def insert_documents(documents, collection_name=@name, check_keys=true, safe=false)
@@ -523,7 +563,7 @@ EOS
523
563
  indexes = []
524
564
  spec.each_pair do |field, direction|
525
565
  indexes.push("#{field}_#{direction}")
526
- end
566
+ end
527
567
  indexes.join("_")
528
568
  end
529
569
  end