mongo 0.18.1 → 0.18.2

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