mongo 0.18.3 → 0.19
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +41 -50
- data/Rakefile +14 -4
- data/examples/gridfs.rb +25 -70
- data/lib/mongo.rb +4 -2
- data/lib/mongo/collection.rb +70 -89
- data/lib/mongo/connection.rb +203 -43
- data/lib/mongo/cursor.rb +7 -7
- data/lib/mongo/db.rb +61 -18
- data/lib/mongo/exceptions.rb +7 -1
- data/lib/mongo/gridfs.rb +8 -1
- data/lib/mongo/gridfs/chunk.rb +2 -1
- data/lib/mongo/gridfs/grid.rb +90 -0
- data/lib/mongo/gridfs/grid_file_system.rb +113 -0
- data/lib/mongo/gridfs/grid_io.rb +339 -0
- data/lib/mongo/gridfs/grid_store.rb +43 -18
- data/lib/mongo/types/binary.rb +5 -1
- data/lib/mongo/types/code.rb +1 -1
- data/lib/mongo/types/dbref.rb +3 -1
- data/lib/mongo/types/min_max_keys.rb +1 -1
- data/lib/mongo/types/objectid.rb +16 -55
- data/lib/mongo/types/regexp_of_holding.rb +1 -1
- data/lib/mongo/util/bson_c.rb +2 -2
- data/lib/mongo/util/bson_ruby.rb +22 -11
- data/lib/mongo/util/byte_buffer.rb +1 -1
- data/lib/mongo/util/conversions.rb +1 -1
- data/lib/mongo/util/ordered_hash.rb +6 -1
- data/lib/mongo/util/server_version.rb +1 -1
- data/lib/mongo/util/support.rb +1 -1
- data/mongo-ruby-driver.gemspec +1 -1
- data/test/auxillary/authentication_test.rb +68 -0
- data/test/auxillary/autoreconnect_test.rb +41 -0
- data/test/binary_test.rb +15 -0
- data/test/{test_bson.rb → bson_test.rb} +63 -6
- data/test/{test_byte_buffer.rb → byte_buffer_test.rb} +0 -0
- data/test/{test_chunk.rb → chunk_test.rb} +0 -0
- data/test/{test_collection.rb → collection_test.rb} +35 -39
- data/test/{test_connection.rb → connection_test.rb} +33 -3
- data/test/{test_conversions.rb → conversions_test.rb} +0 -0
- data/test/{test_cursor.rb → cursor_test.rb} +0 -7
- data/test/{test_db_api.rb → db_api_test.rb} +3 -6
- data/test/{test_db_connection.rb → db_connection_test.rb} +0 -0
- data/test/{test_db.rb → db_test.rb} +33 -15
- data/test/grid_file_system_test.rb +210 -0
- data/test/grid_io_test.rb +78 -0
- data/test/{test_grid_store.rb → grid_store_test.rb} +33 -2
- data/test/grid_test.rb +87 -0
- data/test/{test_objectid.rb → objectid_test.rb} +2 -33
- data/test/{test_ordered_hash.rb → ordered_hash_test.rb} +4 -0
- data/test/{test_slave_connection.rb → slave_connection_test.rb} +0 -0
- data/test/test_helper.rb +2 -2
- data/test/{test_threading.rb → threading_test.rb} +0 -0
- data/test/unit/collection_test.rb +12 -3
- data/test/unit/connection_test.rb +85 -24
- data/test/unit/cursor_test.rb +1 -2
- data/test/unit/db_test.rb +70 -69
- metadata +27 -23
- data/bin/objectid_benchmark.rb +0 -23
- data/bin/perf.rb +0 -30
- data/lib/mongo/admin.rb +0 -95
- data/lib/mongo/util/xml_to_ruby.rb +0 -112
- data/test/test_admin.rb +0 -67
- data/test/test_round_trip.rb +0 -114
data/README.rdoc
CHANGED
@@ -9,15 +9,15 @@ Here's a quick code sample. See the MongoDB Ruby Tutorial
|
|
9
9
|
require 'mongo'
|
10
10
|
include Mongo
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
db = Connection.new.db('sample-db')
|
13
|
+
coll = db.collection('test')
|
14
14
|
|
15
|
-
|
15
|
+
coll.remove
|
16
16
|
3.times do |i|
|
17
|
-
|
17
|
+
coll.insert({'a' => i+1})
|
18
18
|
end
|
19
|
-
puts "There are #{
|
20
|
-
|
19
|
+
puts "There are #{coll.count()} records. Here they are:"
|
20
|
+
coll.find().each { |doc| puts doc.inspect }
|
21
21
|
|
22
22
|
= Installation
|
23
23
|
|
@@ -25,7 +25,6 @@ The driver's gems are hosted on Gemcutter[http://gemcutter.org]. If you haven't
|
|
25
25
|
installed a gem from Gemcutter before, you'll need to set up Gemcutter first:
|
26
26
|
|
27
27
|
$ gem install gemcutter
|
28
|
-
$ gem tumble
|
29
28
|
|
30
29
|
Once you've installed Gemcutter, install the mongo gem as follows:
|
31
30
|
|
@@ -70,40 +69,51 @@ Here's how to start MongoDB and run the "simple.rb" example:
|
|
70
69
|
|
71
70
|
See also the test code, especially test/test_db_api.rb.
|
72
71
|
|
73
|
-
=
|
72
|
+
= GridFS
|
74
73
|
|
75
|
-
The GridStore class
|
76
|
-
|
77
|
-
details, and see examples/gridfs.rb for code that uses many of the GridStore
|
78
|
-
features (metadata, content type, rewind/seek/tell, etc).
|
74
|
+
Note: The GridStore class has been deprecated. Use either the Grid or GridFileSystem
|
75
|
+
classes to take advantage of GridFS.
|
79
76
|
|
80
|
-
|
81
|
-
|
77
|
+
The Ruby driver include two abstractions for storing large files: Grid and GridFileSystem.
|
78
|
+
The Grid class is a Ruby implementation of MongoDB's GridFS file storage
|
79
|
+
specification. GridFileSystem is essentailly the same, but provides a more filesystem-like API
|
80
|
+
and assumes that filenames are unique.
|
82
81
|
|
83
|
-
|
82
|
+
An instance of both classes represents an individual file store. See the API reference
|
83
|
+
for details, and see examples/gridfs.rb for code that uses many of the Grid
|
84
|
+
features (metadata, content type, seek, tell, etc).
|
84
85
|
|
85
|
-
|
86
|
+
Examples:
|
87
|
+
include Mongo
|
88
|
+
|
89
|
+
# Get a database
|
90
|
+
db = Mongo::Connection.new.db('app-db')
|
86
91
|
|
87
|
-
# Store the text "Hello, world!" in the
|
88
|
-
|
89
|
-
|
92
|
+
# GridFileSystem. Store the text "Hello, world!" in the fs.
|
93
|
+
fs = GridFileSystem.new(db)
|
94
|
+
fs.open('filename', 'w') do |f|
|
95
|
+
f.write "Hello, world!"
|
90
96
|
end
|
91
97
|
|
92
|
-
# Output "Hello, world!"
|
93
|
-
|
98
|
+
# GridFileSystem. Output "Hello, world!"
|
99
|
+
fs = GridFileSystem.new(db)
|
100
|
+
fs.open('filename', 'r') do |f|
|
94
101
|
puts f.read
|
95
102
|
end
|
96
103
|
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
|
104
|
+
# Write a file on disk to the Grid
|
105
|
+
file = File.open('image.jpg')
|
106
|
+
grid = Grid.new(db)
|
107
|
+
id = grid.put(file)
|
101
108
|
|
102
|
-
# Retrieve
|
103
|
-
|
104
|
-
|
105
|
-
end
|
109
|
+
# Retrieve the file
|
110
|
+
file = grid.get(id)
|
111
|
+
file.read
|
106
112
|
|
113
|
+
# Get all the file's metata
|
114
|
+
file.filename
|
115
|
+
file.content_type
|
116
|
+
file.metadata
|
107
117
|
|
108
118
|
= Notes
|
109
119
|
|
@@ -294,8 +304,7 @@ It's also possible to test replica pairs with connection pooling:
|
|
294
304
|
|
295
305
|
===Shoulda and Mocha
|
296
306
|
|
297
|
-
|
298
|
-
follows:
|
307
|
+
Running the test suite requires shoulda and mocha. You can install them as follows:
|
299
308
|
|
300
309
|
$ gem install shoulda
|
301
310
|
$ gem install mocha
|
@@ -305,23 +314,6 @@ can override the default host (localhost) and port (Connection::DEFAULT_PORT) by
|
|
305
314
|
using the environment variables MONGO_RUBY_DRIVER_HOST and
|
306
315
|
MONGO_RUBY_DRIVER_PORT.
|
307
316
|
|
308
|
-
The project mongo-qa (http://github.com/mongodb/mongo-qa) contains many more
|
309
|
-
Mongo driver tests that are language independent. To run thoses tests as part
|
310
|
-
of the "rake test" task, download the code "next to" this directory. So, after
|
311
|
-
installing the mongo-qa code you would have these two directories next to each
|
312
|
-
other:
|
313
|
-
|
314
|
-
$ ls
|
315
|
-
mongo-qa
|
316
|
-
mongo-ruby-driver
|
317
|
-
$ rake test
|
318
|
-
|
319
|
-
The tests run just fine if the mongo-qa directory is not there.
|
320
|
-
|
321
|
-
Additionally, the script bin/validate is used by the mongo-qa project's
|
322
|
-
validator script.
|
323
|
-
|
324
|
-
|
325
317
|
= Documentation
|
326
318
|
|
327
319
|
This documentation is available online at http://api.mongodb.org/ruby. You can
|
@@ -342,7 +334,7 @@ See CREDITS.
|
|
342
334
|
|
343
335
|
= License
|
344
336
|
|
345
|
-
Copyright 2008-
|
337
|
+
Copyright 2008-2010 10gen Inc.
|
346
338
|
|
347
339
|
Licensed under the Apache License, Version 2.0 (the "License");
|
348
340
|
you may not use this file except in compliance with the License.
|
@@ -355,4 +347,3 @@ See CREDITS.
|
|
355
347
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
356
348
|
See the License for the specific language governing permissions and
|
357
349
|
limitations under the License.
|
358
|
-
|
data/Rakefile
CHANGED
@@ -47,7 +47,7 @@ namespace :test do
|
|
47
47
|
end
|
48
48
|
|
49
49
|
Rake::TestTask.new(:functional) do |t|
|
50
|
-
t.test_files = FileList['test
|
50
|
+
t.test_files = FileList['test/*_test.rb']
|
51
51
|
t.verbose = true
|
52
52
|
end
|
53
53
|
|
@@ -76,6 +76,16 @@ namespace :test do
|
|
76
76
|
t.verbose = true
|
77
77
|
end
|
78
78
|
|
79
|
+
Rake::TestTask.new(:auto_reconnect) do |t|
|
80
|
+
t.test_files = FileList['test/auxillary/autoreconnect_test.rb']
|
81
|
+
t.verbose = true
|
82
|
+
end
|
83
|
+
|
84
|
+
Rake::TestTask.new(:authentication) do |t|
|
85
|
+
t.test_files = FileList['test/auxillary/authentication_test.rb']
|
86
|
+
t.verbose = true
|
87
|
+
end
|
88
|
+
|
79
89
|
task :drop_databases do |t|
|
80
90
|
puts "Dropping test database..."
|
81
91
|
require File.join(File.dirname(__FILE__), 'lib', 'mongo')
|
@@ -96,10 +106,10 @@ end
|
|
96
106
|
|
97
107
|
desc "Generate YARD documentation"
|
98
108
|
task :ydoc do
|
99
|
-
|
100
|
-
out = File.join('ydoc',
|
109
|
+
require File.join(File.dirname(__FILE__), 'lib', 'mongo')
|
110
|
+
out = File.join('ydoc', Mongo::VERSION)
|
101
111
|
FileUtils.rm_rf('ydoc')
|
102
|
-
system "yardoc lib/**/*.rb lib/mongo/**/*.rb -o #{out} --title MongoRuby-#{
|
112
|
+
system "yardoc lib/**/*.rb lib/mongo/**/*.rb -e docs/yard_ext.rb -p docs/templates -o #{out} --title MongoRuby-#{Mongo::VERSION}"
|
103
113
|
end
|
104
114
|
|
105
115
|
desc "Publish documentation to mongo.rubyforge.org"
|
data/examples/gridfs.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
def assert
|
3
|
+
raise "Failed!" unless yield
|
4
|
+
end
|
2
5
|
|
3
6
|
require 'mongo'
|
4
|
-
require 'mongo/gridfs'
|
5
|
-
|
6
7
|
include Mongo
|
7
|
-
include GridFS
|
8
8
|
|
9
9
|
host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
|
10
10
|
port = ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT
|
@@ -12,77 +12,32 @@ port = ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT
|
|
12
12
|
puts "Connecting to #{host}:#{port}"
|
13
13
|
db = Connection.new(host, port).db('ruby-mongo-examples')
|
14
14
|
|
15
|
-
|
16
|
-
GridStore.open(db, fname, 'r') { |f| puts f.read }
|
17
|
-
end
|
18
|
-
|
19
|
-
# Write a new file
|
20
|
-
GridStore.open(db, 'foobar', 'w') { |f| f.write("hello, world!") }
|
21
|
-
|
22
|
-
# Read it and print out the contents
|
23
|
-
dump(db, 'foobar')
|
24
|
-
|
25
|
-
# Append more data
|
26
|
-
GridStore.open(db, 'foobar', 'w+') { |f| f.write("\n"); f.puts "line two" }
|
27
|
-
dump(db, 'foobar')
|
15
|
+
data = "hello, world!"
|
28
16
|
|
29
|
-
|
30
|
-
GridStore.open(db, 'foobar', 'w') { |f| f.puts "hello, sailor!" }
|
31
|
-
dump(db, 'foobar')
|
17
|
+
grid = Grid.new(db)
|
32
18
|
|
33
|
-
#
|
34
|
-
|
35
|
-
puts "File 'does-not-exist' exists: #{GridStore.exist?(db, 'does-not-exist')}"
|
19
|
+
# Write a new file. data can be a string or an io object responding to #read.
|
20
|
+
id = grid.put(data, 'hello.txt')
|
36
21
|
|
37
|
-
# Read
|
38
|
-
|
22
|
+
# Read it and print out the contents
|
23
|
+
file = grid.get(id)
|
24
|
+
puts file.read
|
39
25
|
|
40
|
-
#
|
41
|
-
|
42
|
-
f.write "hello, world!"
|
43
|
-
f.rewind
|
44
|
-
f.write "xyzzz"
|
45
|
-
puts f.tell # => 5
|
46
|
-
f.seek(4)
|
47
|
-
f.write('y')
|
48
|
-
}
|
49
|
-
dump(db, 'foobar') # => 'xyzzy'
|
26
|
+
# Delete the file
|
27
|
+
grid.delete(id)
|
50
28
|
|
51
|
-
|
52
|
-
|
53
|
-
|
29
|
+
begin
|
30
|
+
grid.get(id)
|
31
|
+
rescue => e
|
32
|
+
assert {e.class == Mongo::GridError}
|
33
|
+
end
|
54
34
|
|
55
35
|
# Metadata
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
# Add some metadata; change content type
|
65
|
-
GridStore.open(db, 'foobar', 'w+') { |f|
|
66
|
-
f.content_type = 'text/xml'
|
67
|
-
f.metadata = {'a' => 1}
|
68
|
-
}
|
69
|
-
# Print it
|
70
|
-
GridStore.open(db, 'foobar', 'r') { |f|
|
71
|
-
puts f.content_type
|
72
|
-
puts f.upload_date
|
73
|
-
puts f.chunk_size
|
74
|
-
puts f.metadata.inspect
|
75
|
-
}
|
76
|
-
|
77
|
-
# You can also set metadata when initially writing the file. Setting :root
|
78
|
-
# means that the file and its chunks are stored in a different root
|
79
|
-
# collection: instead of gridfs.files and gridfs.chunks, here we use
|
80
|
-
# my_files.files and my_files.chunks.
|
81
|
-
GridStore.open(db, 'foobar', 'w',
|
82
|
-
:content_type => 'text/plain',
|
83
|
-
:metadata => {'a' => 1},
|
84
|
-
:chunk_size => 1024 * 4,
|
85
|
-
:root => 'my_files') { |f|
|
86
|
-
f.puts 'hello, world'
|
87
|
-
}
|
88
|
-
|
36
|
+
id = grid.put(data, 'hello.txt', :content_type => 'text/plain', :metadata => {'name' => 'hello'})
|
37
|
+
file = grid.get(id)
|
38
|
+
|
39
|
+
p file.content_type
|
40
|
+
p file.metadata.inspect
|
41
|
+
p file.chunk_size
|
42
|
+
p file.file_length
|
43
|
+
p file.data
|
data/lib/mongo.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
2
|
|
3
3
|
module Mongo
|
4
|
-
VERSION = "0.
|
4
|
+
VERSION = "0.19"
|
5
5
|
end
|
6
6
|
|
7
7
|
begin
|
@@ -52,10 +52,12 @@ require 'mongo/util/conversions'
|
|
52
52
|
require 'mongo/util/server_version'
|
53
53
|
require 'mongo/util/bson_ruby'
|
54
54
|
|
55
|
-
require 'mongo/admin'
|
56
55
|
require 'mongo/collection'
|
57
56
|
require 'mongo/connection'
|
58
57
|
require 'mongo/cursor'
|
59
58
|
require 'mongo/db'
|
60
59
|
require 'mongo/exceptions'
|
61
60
|
require 'mongo/gridfs'
|
61
|
+
require 'mongo/gridfs/grid'
|
62
|
+
require 'mongo/gridfs/grid_io'
|
63
|
+
require 'mongo/gridfs/grid_file_system'
|
data/lib/mongo/collection.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# --
|
2
|
-
# Copyright (C) 2008-
|
2
|
+
# Copyright (C) 2008-2010 10gen Inc.
|
3
3
|
#
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
5
|
# you may not use this file except in compliance with the License.
|
@@ -33,6 +33,8 @@ module Mongo
|
|
33
33
|
# if collection name is not a string or symbol
|
34
34
|
#
|
35
35
|
# @return [Collection]
|
36
|
+
#
|
37
|
+
# @core collections constructor_details
|
36
38
|
def initialize(db, name, pk_factory=nil)
|
37
39
|
case name
|
38
40
|
when Symbol, String
|
@@ -126,6 +128,8 @@ module Mongo
|
|
126
128
|
#
|
127
129
|
# @raise [RuntimeError]
|
128
130
|
# if given unknown options
|
131
|
+
#
|
132
|
+
# @core find find-instance_method
|
129
133
|
def find(selector={}, opts={})
|
130
134
|
fields = opts.delete(:fields)
|
131
135
|
fields = ["_id"] if fields && fields.empty?
|
@@ -221,6 +225,8 @@ module Mongo
|
|
221
225
|
# If true, check that the save succeeded. OperationFailure
|
222
226
|
# will be raised on an error. Note that a safe check requires an extra
|
223
227
|
# round-trip to the database.
|
228
|
+
#
|
229
|
+
# @core insert insert-instance_method
|
224
230
|
def insert(doc_or_docs, options={})
|
225
231
|
doc_or_docs = [doc_or_docs] unless doc_or_docs.is_a?(Array)
|
226
232
|
doc_or_docs.collect! { |doc| @pk_factory.create_pk(doc) }
|
@@ -248,15 +254,17 @@ module Mongo
|
|
248
254
|
#
|
249
255
|
# @raise [Mongo::OperationFailure] an exception will be raised iff safe mode is enabled
|
250
256
|
# and the operation fails.
|
257
|
+
#
|
258
|
+
# @core remove remove-instance_method
|
251
259
|
def remove(selector={}, opts={})
|
252
260
|
# Initial byte is 0.
|
253
261
|
message = ByteBuffer.new([0, 0, 0, 0])
|
254
262
|
BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{@name}")
|
255
263
|
message.put_int(0)
|
256
|
-
message.put_array(BSON.serialize(selector, false).to_a)
|
264
|
+
message.put_array(BSON.serialize(selector, false, true).to_a)
|
257
265
|
|
258
266
|
if opts[:safe]
|
259
|
-
@connection.send_message_with_safe_check(Mongo::Constants::OP_DELETE, message,
|
267
|
+
@connection.send_message_with_safe_check(Mongo::Constants::OP_DELETE, message, @db.name,
|
260
268
|
"db.#{@db.name}.remove(#{selector.inspect})")
|
261
269
|
# the return value of send_message_with_safe_check isn't actually meaningful --
|
262
270
|
# only the fact that it didn't raise an error is -- so just return true
|
@@ -285,6 +293,8 @@ module Mongo
|
|
285
293
|
# If true, check that the save succeeded. OperationFailure
|
286
294
|
# will be raised on an error. Note that a safe check requires an extra
|
287
295
|
# round-trip to the database.
|
296
|
+
#
|
297
|
+
# @core update update-instance_method
|
288
298
|
def update(selector, document, options={})
|
289
299
|
# Initial byte is 0.
|
290
300
|
message = ByteBuffer.new([0, 0, 0, 0])
|
@@ -293,8 +303,8 @@ module Mongo
|
|
293
303
|
update_options += 1 if options[:upsert]
|
294
304
|
update_options += 2 if options[:multi]
|
295
305
|
message.put_int(update_options)
|
296
|
-
message.put_array(BSON.serialize(selector, false).to_a)
|
297
|
-
message.put_array(BSON.serialize(document, false).to_a)
|
306
|
+
message.put_array(BSON.serialize(selector, false, true).to_a)
|
307
|
+
message.put_array(BSON.serialize(document, false, true).to_a)
|
298
308
|
if options[:safe]
|
299
309
|
@connection.send_message_with_safe_check(Mongo::Constants::OP_UPDATE, message, @db.name,
|
300
310
|
"db.#{@name}.update(#{selector.inspect}, #{document.inspect})")
|
@@ -313,6 +323,8 @@ module Mongo
|
|
313
323
|
# @param [Boolean] unique if true, this index will enforce a uniqueness constraint.
|
314
324
|
#
|
315
325
|
# @return [String] the name of the index created.
|
326
|
+
#
|
327
|
+
# @core indexes create_index-instance_method
|
316
328
|
def create_index(field_or_spec, unique=false)
|
317
329
|
field_h = OrderedHash.new
|
318
330
|
if field_or_spec.is_a?(String) || field_or_spec.is_a?(Symbol)
|
@@ -326,18 +338,26 @@ module Mongo
|
|
326
338
|
:ns => "#{@db.name}.#{@name}",
|
327
339
|
:key => field_h,
|
328
340
|
:unique => unique }
|
329
|
-
|
341
|
+
begin
|
342
|
+
insert_documents([sel], Mongo::DB::SYSTEM_INDEX_COLLECTION, false, true)
|
343
|
+
rescue Mongo::OperationFailure
|
344
|
+
raise Mongo::OperationFailure, "Failed to create index #{sel.inspect}."
|
345
|
+
end
|
330
346
|
name
|
331
347
|
end
|
332
348
|
|
333
349
|
# Drop a specified index.
|
334
350
|
#
|
335
351
|
# @param [String] name
|
352
|
+
#
|
353
|
+
# @core indexes
|
336
354
|
def drop_index(name)
|
337
355
|
@db.drop_index(@name, name)
|
338
356
|
end
|
339
357
|
|
340
358
|
# Drop all indexes.
|
359
|
+
#
|
360
|
+
# @core indexes
|
341
361
|
def drop_indexes
|
342
362
|
|
343
363
|
# Note: calling drop_indexes with no args will drop them all.
|
@@ -369,6 +389,8 @@ module Mongo
|
|
369
389
|
# @return [Collection] a collection containing the results of the operation.
|
370
390
|
#
|
371
391
|
# @see http://www.mongodb.org/display/DOCS/MapReduce Offical MongoDB map/reduce documentation.
|
392
|
+
#
|
393
|
+
# @core mapreduce map_reduce-instance_method
|
372
394
|
def map_reduce(map, reduce, opts={})
|
373
395
|
map = Code.new(map) unless map.is_a?(Code)
|
374
396
|
reduce = Code.new(reduce) unless reduce.is_a?(Code)
|
@@ -397,100 +419,57 @@ module Mongo
|
|
397
419
|
# @param [String, Code] finalize :: optional. a JavaScript function that receives and modifies
|
398
420
|
# each of the resultant grouped objects. Available only when group is run
|
399
421
|
# with command set to true.
|
400
|
-
# @param [
|
401
|
-
#
|
422
|
+
# @param [Nil] deprecated this param in a placeholder for a deprecated param. It will be removed
|
423
|
+
# in the next release.
|
402
424
|
#
|
403
425
|
# @return [Array] the grouped items.
|
404
|
-
def group(key, condition, initial, reduce,
|
426
|
+
def group(key, condition, initial, reduce, finalize=nil, deprecated=nil)
|
405
427
|
|
406
|
-
|
428
|
+
# Warn of changed API post eval deprecation.
|
429
|
+
if finalize == true || finalize == false || deprecated
|
430
|
+
warn "The API for Collection#group has changed. 'Finalize' is now the fifth parameter, " +
|
431
|
+
"since it's no longer necessary to specify whether #group is run as a command. " +
|
432
|
+
"See http://api.mongodb.org/ruby/current/Mongo/Collection.html#group-instance_method for details."
|
433
|
+
end
|
407
434
|
|
408
|
-
|
435
|
+
reduce = Code.new(reduce) unless reduce.is_a?(Code)
|
409
436
|
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
}
|
437
|
+
group_command = {
|
438
|
+
"group" => {
|
439
|
+
"ns" => @name,
|
440
|
+
"$reduce" => reduce,
|
441
|
+
"cond" => condition,
|
442
|
+
"initial" => initial
|
417
443
|
}
|
444
|
+
}
|
418
445
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
else
|
425
|
-
key_type = "$keyf"
|
426
|
-
key_value = key.is_a?(Code) ? key : Code.new(key)
|
427
|
-
end
|
428
|
-
|
429
|
-
group_command["group"][key_type] = key_value
|
430
|
-
end
|
431
|
-
|
432
|
-
# only add finalize if specified
|
433
|
-
if finalize
|
434
|
-
finalize = Code.new(finalize) unless finalize.is_a?(Code)
|
435
|
-
group_command['group']['finalize'] = finalize
|
436
|
-
end
|
437
|
-
|
438
|
-
result = @db.command group_command
|
439
|
-
|
440
|
-
if result["ok"] == 1
|
441
|
-
return result["retval"]
|
446
|
+
unless key.nil?
|
447
|
+
if key.is_a? Array
|
448
|
+
key_type = "key"
|
449
|
+
key_value = {}
|
450
|
+
key.each { |k| key_value[k] = 1 }
|
442
451
|
else
|
443
|
-
|
452
|
+
key_type = "$keyf"
|
453
|
+
key_value = key.is_a?(Code) ? key : Code.new(key)
|
444
454
|
end
|
445
455
|
|
446
|
-
|
447
|
-
|
448
|
-
warn "Collection#group must now be run as a command; you can do this by passing 'true' as the command argument."
|
449
|
-
|
450
|
-
raise OperationFailure, ":finalize can be specified only when " +
|
451
|
-
"group is run as a command (set command param to true)" if finalize
|
456
|
+
group_command["group"][key_type] = key_value
|
457
|
+
end
|
452
458
|
|
453
|
-
|
454
|
-
|
459
|
+
# only add finalize if specified
|
460
|
+
# check to see if users have sent the finalizer as the last argument.
|
461
|
+
finalize = deprecated if deprecated.is_a?(String) || deprecated.is_a?(Code)
|
462
|
+
finalize = Code.new(finalize) if finalize.is_a?(String)
|
463
|
+
if finalize.is_a?(Code)
|
464
|
+
group_command['group']['finalize'] = finalize
|
465
|
+
end
|
455
466
|
|
456
|
-
|
457
|
-
when Code
|
458
|
-
scope = reduce.scope
|
459
|
-
else
|
460
|
-
scope = {}
|
461
|
-
end
|
462
|
-
scope.merge!({
|
463
|
-
"ns" => @name,
|
464
|
-
"keys" => key,
|
465
|
-
"condition" => condition,
|
466
|
-
"initial" => initial })
|
467
|
-
|
468
|
-
group_function = <<EOS
|
469
|
-
function () {
|
470
|
-
var c = db[ns].find(condition);
|
471
|
-
var map = new Map();
|
472
|
-
var reduce_function = #{reduce};
|
473
|
-
while (c.hasNext()) {
|
474
|
-
var obj = c.next();
|
475
|
-
|
476
|
-
var key = {};
|
477
|
-
for (var i = 0; i < keys.length; i++) {
|
478
|
-
var k = keys[i];
|
479
|
-
key[k] = obj[k];
|
480
|
-
}
|
467
|
+
result = @db.command group_command
|
481
468
|
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
map.put(key, aggObj);
|
487
|
-
}
|
488
|
-
reduce_function(obj, aggObj);
|
489
|
-
}
|
490
|
-
return {"result": map.values()};
|
491
|
-
}
|
492
|
-
EOS
|
493
|
-
@db.eval(Code.new(group_function, scope))["result"]
|
469
|
+
if result["ok"] == 1
|
470
|
+
result["retval"]
|
471
|
+
else
|
472
|
+
raise OperationFailure, "group command failed: #{result['errmsg']}"
|
494
473
|
end
|
495
474
|
end
|
496
475
|
|
@@ -534,7 +513,7 @@ EOS
|
|
534
513
|
# Note: If operating in auth mode, the client must be authorized as an admin to
|
535
514
|
# perform this operation.
|
536
515
|
#
|
537
|
-
# @param [String
|
516
|
+
# @param [String] new_name the new name for this collection
|
538
517
|
#
|
539
518
|
# @raise [InvalidName] if +new_name+ is an invalid collection name.
|
540
519
|
def rename(new_name)
|
@@ -562,6 +541,8 @@ EOS
|
|
562
541
|
# Get information on the indexes for this collection.
|
563
542
|
#
|
564
543
|
# @return [Hash] a hash where the keys are index names.
|
544
|
+
#
|
545
|
+
# @core indexes
|
565
546
|
def index_information
|
566
547
|
@db.index_information(@name)
|
567
548
|
end
|
@@ -609,7 +590,7 @@ EOS
|
|
609
590
|
# Initial byte is 0.
|
610
591
|
message = ByteBuffer.new([0, 0, 0, 0])
|
611
592
|
BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{collection_name}")
|
612
|
-
documents.each { |doc| message.put_array(BSON.serialize(doc, check_keys).to_a) }
|
593
|
+
documents.each { |doc| message.put_array(BSON.serialize(doc, check_keys, true).to_a) }
|
613
594
|
if safe
|
614
595
|
@connection.send_message_with_safe_check(Mongo::Constants::OP_INSERT, message, @db.name,
|
615
596
|
"db.#{collection_name}.insert(#{documents.inspect})")
|