jmongo 1.0.3 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +8 -0
- data/Gemfile.lock +43 -0
- data/Rakefile +72 -0
- data/jmongo.gemspec +84 -6
- data/lib/jmongo.rb +6 -14
- data/lib/jmongo/collection.rb +196 -114
- data/lib/jmongo/connection.rb +39 -13
- data/lib/jmongo/cursor.rb +161 -63
- data/lib/jmongo/db.rb +119 -30
- data/lib/jmongo/exceptions.rb +39 -0
- data/lib/jmongo/mongo-2.6.5.gb1.jar +0 -0
- data/lib/jmongo/mongo/bson.rb +130 -0
- data/lib/jmongo/mongo/collection.rb +185 -0
- data/lib/jmongo/mongo/connection.rb +45 -0
- data/lib/jmongo/mongo/db.rb +31 -0
- data/lib/jmongo/mongo/jmongo.rb +44 -0
- data/lib/jmongo/mongo/mongo.rb +98 -0
- data/lib/jmongo/mongo/ruby_ext.rb +38 -0
- data/lib/jmongo/mongo/utils.rb +136 -0
- data/lib/jmongo/version.rb +1 -1
- data/test-results.txt +98 -0
- data/test/auxillary/1.4_features.rb +166 -0
- data/test/auxillary/authentication_test.rb +68 -0
- data/test/auxillary/autoreconnect_test.rb +41 -0
- data/test/auxillary/fork_test.rb +30 -0
- data/test/auxillary/repl_set_auth_test.rb +58 -0
- data/test/auxillary/slave_connection_test.rb +36 -0
- data/test/auxillary/threaded_authentication_test.rb +101 -0
- data/test/bson/binary_test.rb +15 -0
- data/test/bson/bson_test.rb +657 -0
- data/test/bson/byte_buffer_test.rb +208 -0
- data/test/bson/hash_with_indifferent_access_test.rb +38 -0
- data/test/bson/json_test.rb +17 -0
- data/test/bson/object_id_test.rb +138 -0
- data/test/bson/ordered_hash_test.rb +245 -0
- data/test/bson/test_helper.rb +46 -0
- data/test/bson/timestamp_test.rb +46 -0
- data/test/collection_test.rb +933 -0
- data/test/connection_test.rb +325 -0
- data/test/conversions_test.rb +121 -0
- data/test/cursor_fail_test.rb +75 -0
- data/test/cursor_message_test.rb +43 -0
- data/test/cursor_test.rb +547 -0
- data/test/data/empty_data +0 -0
- data/test/data/sample_data +0 -0
- data/test/data/sample_file.pdf +0 -0
- data/test/data/small_data.txt +1 -0
- data/test/db_api_test.rb +739 -0
- data/test/db_connection_test.rb +15 -0
- data/test/db_test.rb +325 -0
- data/test/grid_file_system_test.rb +260 -0
- data/test/grid_io_test.rb +210 -0
- data/test/grid_test.rb +259 -0
- data/test/load/thin/config.ru +6 -0
- data/test/load/thin/config.yml.template +6 -0
- data/test/load/thin/load.rb +24 -0
- data/test/load/unicorn/config.ru +6 -0
- data/test/load/unicorn/load.rb +23 -0
- data/test/load/unicorn/unicorn.rb.template +29 -0
- data/test/replica_sets/connect_test.rb +111 -0
- data/test/replica_sets/connection_string_test.rb +29 -0
- data/test/replica_sets/count_test.rb +36 -0
- data/test/replica_sets/insert_test.rb +54 -0
- data/test/replica_sets/pooled_insert_test.rb +58 -0
- data/test/replica_sets/query_secondaries.rb +109 -0
- data/test/replica_sets/query_test.rb +52 -0
- data/test/replica_sets/read_preference_test.rb +43 -0
- data/test/replica_sets/refresh_test.rb +123 -0
- data/test/replica_sets/replication_ack_test.rb +71 -0
- data/test/replica_sets/rs_test_helper.rb +27 -0
- data/test/safe_test.rb +68 -0
- data/test/support/hash_with_indifferent_access.rb +186 -0
- data/test/support/keys.rb +45 -0
- data/test/support_test.rb +19 -0
- data/test/test_helper.rb +111 -0
- data/test/threading/threading_with_large_pool_test.rb +90 -0
- data/test/threading_test.rb +88 -0
- data/test/tools/auth_repl_set_manager.rb +14 -0
- data/test/tools/keyfile.txt +1 -0
- data/test/tools/repl_set_manager.rb +377 -0
- data/test/unit/collection_test.rb +128 -0
- data/test/unit/connection_test.rb +85 -0
- data/test/unit/cursor_test.rb +127 -0
- data/test/unit/db_test.rb +96 -0
- data/test/unit/grid_test.rb +51 -0
- data/test/unit/node_test.rb +73 -0
- data/test/unit/pool_manager_test.rb +47 -0
- data/test/unit/pool_test.rb +9 -0
- data/test/unit/read_test.rb +101 -0
- data/test/unit/safe_test.rb +125 -0
- data/test/uri_test.rb +92 -0
- metadata +170 -99
- data/lib/jmongo/ajrb.rb +0 -189
- data/lib/jmongo/jmongo_jext.rb +0 -302
- data/lib/jmongo/mongo-2.6.3.jar +0 -0
- data/lib/jmongo/utils.rb +0 -61
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
jmongo (1.0.3)
|
5
|
+
require_all (~> 1.2)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
awesome_print (0.4.0)
|
11
|
+
diff-lcs (1.1.3)
|
12
|
+
fuubar (0.0.6)
|
13
|
+
rspec (~> 2.0)
|
14
|
+
rspec-instafail (~> 0.1.8)
|
15
|
+
ruby-progressbar (~> 0.0.10)
|
16
|
+
metaclass (0.0.1)
|
17
|
+
mocha (0.10.0)
|
18
|
+
metaclass (~> 0.0.1)
|
19
|
+
rake (0.9.2)
|
20
|
+
require_all (1.2.0)
|
21
|
+
rspec (2.6.0)
|
22
|
+
rspec-core (~> 2.6.0)
|
23
|
+
rspec-expectations (~> 2.6.0)
|
24
|
+
rspec-mocks (~> 2.6.0)
|
25
|
+
rspec-core (2.6.4)
|
26
|
+
rspec-expectations (2.6.0)
|
27
|
+
diff-lcs (~> 1.1.2)
|
28
|
+
rspec-instafail (0.1.8)
|
29
|
+
rspec-mocks (2.6.0)
|
30
|
+
ruby-progressbar (0.0.10)
|
31
|
+
shoulda (2.11.3)
|
32
|
+
|
33
|
+
PLATFORMS
|
34
|
+
java
|
35
|
+
|
36
|
+
DEPENDENCIES
|
37
|
+
awesome_print (~> 0.4)
|
38
|
+
fuubar (~> 0.0)
|
39
|
+
jmongo!
|
40
|
+
mocha
|
41
|
+
rake
|
42
|
+
rspec (~> 2.6)
|
43
|
+
shoulda
|
data/Rakefile
CHANGED
@@ -116,3 +116,75 @@ task :validate do
|
|
116
116
|
exit!
|
117
117
|
end
|
118
118
|
end
|
119
|
+
|
120
|
+
require 'rake/testtask'
|
121
|
+
|
122
|
+
task :test do
|
123
|
+
puts "\nTo test the pure jruby driver: \nrake test:jruby\n\n"
|
124
|
+
end
|
125
|
+
|
126
|
+
namespace :test do
|
127
|
+
|
128
|
+
desc "Test the driver using pure jruby (no C extension)"
|
129
|
+
task :jruby do
|
130
|
+
ENV['C_EXT'] = nil
|
131
|
+
if ENV['TEST']
|
132
|
+
Rake::Task['test:functional'].invoke
|
133
|
+
else
|
134
|
+
Rake::Task['test:unit'].invoke
|
135
|
+
Rake::Task['test:functional'].invoke
|
136
|
+
Rake::Task['test:bson'].invoke
|
137
|
+
Rake::Task['test:pooled_threading'].invoke
|
138
|
+
Rake::Task['test:drop_databases'].invoke
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
desc "Run the replica set test suite"
|
143
|
+
Rake::TestTask.new(:rs) do |t|
|
144
|
+
t.test_files = FileList['test/replica_sets/*_test.rb']
|
145
|
+
t.verbose = true
|
146
|
+
t.ruby_opts << '-w'
|
147
|
+
end
|
148
|
+
|
149
|
+
Rake::TestTask.new(:unit) do |t|
|
150
|
+
t.test_files = FileList['test/unit/*_test.rb']
|
151
|
+
t.verbose = true
|
152
|
+
t.ruby_opts << '-w'
|
153
|
+
end
|
154
|
+
|
155
|
+
Rake::TestTask.new(:functional) do |t|
|
156
|
+
t.test_files = FileList['test/*_test.rb']
|
157
|
+
t.verbose = true
|
158
|
+
t.ruby_opts << '-w'
|
159
|
+
end
|
160
|
+
|
161
|
+
Rake::TestTask.new(:pooled_threading) do |t|
|
162
|
+
t.test_files = FileList['test/threading/*_test.rb']
|
163
|
+
t.verbose = true
|
164
|
+
t.ruby_opts << '-w'
|
165
|
+
end
|
166
|
+
|
167
|
+
Rake::TestTask.new(:auto_reconnect) do |t|
|
168
|
+
t.test_files = FileList['test/auxillary/autoreconnect_test.rb']
|
169
|
+
t.verbose = true
|
170
|
+
t.ruby_opts << '-w'
|
171
|
+
end
|
172
|
+
|
173
|
+
Rake::TestTask.new(:authentication) do |t|
|
174
|
+
t.test_files = FileList['test/auxillary/authentication_test.rb']
|
175
|
+
t.verbose = true
|
176
|
+
t.ruby_opts << '-w'
|
177
|
+
end
|
178
|
+
|
179
|
+
Rake::TestTask.new(:new_features) do |t|
|
180
|
+
t.test_files = FileList['test/auxillary/1.4_features.rb']
|
181
|
+
t.verbose = true
|
182
|
+
t.ruby_opts << '-w'
|
183
|
+
end
|
184
|
+
|
185
|
+
Rake::TestTask.new(:bson) do |t|
|
186
|
+
t.test_files = FileList['test/bson/*_test.rb']
|
187
|
+
t.verbose = true
|
188
|
+
t.ruby_opts << '-w'
|
189
|
+
end
|
190
|
+
end
|
data/jmongo.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'jmongo'
|
3
|
-
s.version = '1.0
|
4
|
-
s.date = '2011-
|
3
|
+
s.version = '1.1.0'
|
4
|
+
s.date = '2011-10-03'
|
5
5
|
s.platform = Gem::Platform::RUBY
|
6
6
|
s.authors = ["Chuck Remes","Guy Boertje", "Lee Henson"]
|
7
7
|
s.email = ["cremes@mac.com", "guyboertje@gmail.com", "lee.m.henson@gmail.com"]
|
@@ -11,6 +11,8 @@ Gem::Specification.new do |s|
|
|
11
11
|
|
12
12
|
# = MANIFEST =
|
13
13
|
s.files = %w[
|
14
|
+
Gemfile
|
15
|
+
Gemfile.lock
|
14
16
|
History.txt
|
15
17
|
LICENSE.txt
|
16
18
|
README.txt
|
@@ -18,18 +20,94 @@ Gem::Specification.new do |s|
|
|
18
20
|
bin/jmongo
|
19
21
|
jmongo.gemspec
|
20
22
|
lib/jmongo.rb
|
21
|
-
lib/jmongo/ajrb.rb
|
22
23
|
lib/jmongo/collection.rb
|
23
24
|
lib/jmongo/connection.rb
|
24
25
|
lib/jmongo/cursor.rb
|
25
26
|
lib/jmongo/db.rb
|
26
27
|
lib/jmongo/exceptions.rb
|
27
|
-
lib/jmongo/
|
28
|
-
lib/jmongo/mongo
|
29
|
-
lib/jmongo/
|
28
|
+
lib/jmongo/mongo-2.6.5.gb1.jar
|
29
|
+
lib/jmongo/mongo/bson.rb
|
30
|
+
lib/jmongo/mongo/collection.rb
|
31
|
+
lib/jmongo/mongo/connection.rb
|
32
|
+
lib/jmongo/mongo/db.rb
|
33
|
+
lib/jmongo/mongo/jmongo.rb
|
34
|
+
lib/jmongo/mongo/mongo.rb
|
35
|
+
lib/jmongo/mongo/ruby_ext.rb
|
36
|
+
lib/jmongo/mongo/utils.rb
|
30
37
|
lib/jmongo/version.rb
|
31
38
|
spec/jmongo_spec.rb
|
32
39
|
spec/spec_helper.rb
|
40
|
+
test-results.txt
|
41
|
+
test/auxillary/1.4_features.rb
|
42
|
+
test/auxillary/authentication_test.rb
|
43
|
+
test/auxillary/autoreconnect_test.rb
|
44
|
+
test/auxillary/fork_test.rb
|
45
|
+
test/auxillary/repl_set_auth_test.rb
|
46
|
+
test/auxillary/slave_connection_test.rb
|
47
|
+
test/auxillary/threaded_authentication_test.rb
|
48
|
+
test/bson/binary_test.rb
|
49
|
+
test/bson/bson_test.rb
|
50
|
+
test/bson/byte_buffer_test.rb
|
51
|
+
test/bson/hash_with_indifferent_access_test.rb
|
52
|
+
test/bson/json_test.rb
|
53
|
+
test/bson/object_id_test.rb
|
54
|
+
test/bson/ordered_hash_test.rb
|
55
|
+
test/bson/test_helper.rb
|
56
|
+
test/bson/timestamp_test.rb
|
57
|
+
test/collection_test.rb
|
58
|
+
test/connection_test.rb
|
59
|
+
test/conversions_test.rb
|
60
|
+
test/cursor_fail_test.rb
|
61
|
+
test/cursor_message_test.rb
|
62
|
+
test/cursor_test.rb
|
63
|
+
test/data/empty_data
|
64
|
+
test/data/sample_data
|
65
|
+
test/data/sample_file.pdf
|
66
|
+
test/data/small_data.txt
|
67
|
+
test/db_api_test.rb
|
68
|
+
test/db_connection_test.rb
|
69
|
+
test/db_test.rb
|
70
|
+
test/grid_file_system_test.rb
|
71
|
+
test/grid_io_test.rb
|
72
|
+
test/grid_test.rb
|
73
|
+
test/load/thin/config.ru
|
74
|
+
test/load/thin/config.yml.template
|
75
|
+
test/load/thin/load.rb
|
76
|
+
test/load/unicorn/config.ru
|
77
|
+
test/load/unicorn/load.rb
|
78
|
+
test/load/unicorn/unicorn.rb.template
|
79
|
+
test/replica_sets/connect_test.rb
|
80
|
+
test/replica_sets/connection_string_test.rb
|
81
|
+
test/replica_sets/count_test.rb
|
82
|
+
test/replica_sets/insert_test.rb
|
83
|
+
test/replica_sets/pooled_insert_test.rb
|
84
|
+
test/replica_sets/query_secondaries.rb
|
85
|
+
test/replica_sets/query_test.rb
|
86
|
+
test/replica_sets/read_preference_test.rb
|
87
|
+
test/replica_sets/refresh_test.rb
|
88
|
+
test/replica_sets/replication_ack_test.rb
|
89
|
+
test/replica_sets/rs_test_helper.rb
|
90
|
+
test/safe_test.rb
|
91
|
+
test/support/hash_with_indifferent_access.rb
|
92
|
+
test/support/keys.rb
|
93
|
+
test/support_test.rb
|
94
|
+
test/test_helper.rb
|
95
|
+
test/threading/threading_with_large_pool_test.rb
|
96
|
+
test/threading_test.rb
|
97
|
+
test/tools/auth_repl_set_manager.rb
|
98
|
+
test/tools/keyfile.txt
|
99
|
+
test/tools/repl_set_manager.rb
|
100
|
+
test/unit/collection_test.rb
|
101
|
+
test/unit/connection_test.rb
|
102
|
+
test/unit/cursor_test.rb
|
103
|
+
test/unit/db_test.rb
|
104
|
+
test/unit/grid_test.rb
|
105
|
+
test/unit/node_test.rb
|
106
|
+
test/unit/pool_manager_test.rb
|
107
|
+
test/unit/pool_test.rb
|
108
|
+
test/unit/read_test.rb
|
109
|
+
test/unit/safe_test.rb
|
110
|
+
test/uri_test.rb
|
33
111
|
]
|
34
112
|
# = MANIFEST =
|
35
113
|
|
data/lib/jmongo.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
# Copyright (C) 2010 Chuck Remes
|
1
|
+
# Copyright (C) 2010 Chuck Remes, Guy Boertje
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in
|
4
|
+
# you may not use this file except in coSmpliance with the License.
|
5
5
|
# You may obtain a copy of the License at
|
6
6
|
#
|
7
7
|
# http://www.apache.org/licenses/LICENSE-2.0
|
@@ -17,19 +17,11 @@ unless RUBY_PLATFORM =~ /java/
|
|
17
17
|
exit 255
|
18
18
|
end
|
19
19
|
|
20
|
+
require 'timeout'
|
21
|
+
require 'java'
|
22
|
+
|
20
23
|
require 'require_all'
|
21
24
|
require_rel 'jmongo/*.jar'
|
22
25
|
|
23
|
-
|
24
|
-
require 'jmongo/jmongo_jext'
|
25
|
-
require_rel 'jmongo/*.rb'
|
26
|
-
|
27
|
-
module Mongo
|
28
|
-
ASCENDING = 1
|
29
|
-
DESCENDING = -1
|
30
|
-
GEO2D = '2d'
|
26
|
+
require_rel 'jmongo/**/*.rb'
|
31
27
|
|
32
|
-
module Constants
|
33
|
-
DEFAULT_BATCH_SIZE = 100
|
34
|
-
end
|
35
|
-
end
|
data/lib/jmongo/collection.rb
CHANGED
@@ -35,30 +35,31 @@ module Mongo
|
|
35
35
|
# @return [Collection]
|
36
36
|
#
|
37
37
|
# @core collections constructor_details
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
#db, name, options=nil, j_collection=nil
|
39
|
+
def initialize(*args)
|
40
|
+
j_collection = nil
|
41
|
+
@opts = {}
|
42
|
+
if args.size == 4
|
43
|
+
j_collection = args.pop
|
43
44
|
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
if name.empty? or name.include? ".."
|
48
|
-
raise Mongo::InvalidNSName, "collection names cannot be empty"
|
45
|
+
if args.size == 3
|
46
|
+
@opts = args.pop
|
49
47
|
end
|
50
|
-
if
|
51
|
-
raise
|
48
|
+
if args.size < 2
|
49
|
+
raise ArgumentError.new("Must supply at least name and db parameters")
|
52
50
|
end
|
53
|
-
if
|
54
|
-
|
51
|
+
if args.first.respond_to?('collection_names')
|
52
|
+
db, name = args
|
53
|
+
else
|
54
|
+
name, db = args
|
55
55
|
end
|
56
56
|
|
57
|
-
@
|
57
|
+
@name = validate_name(name)
|
58
|
+
@db, @j_db = db, db.j_db
|
58
59
|
@connection = @db.connection
|
59
|
-
@pk_factory =
|
60
|
+
@pk_factory = @opts[:pk] || BSON::ObjectId
|
60
61
|
@hint = nil
|
61
|
-
@j_collection = @j_db.
|
62
|
+
@j_collection = j_collection || @j_db.get_collection(@name)
|
62
63
|
end
|
63
64
|
|
64
65
|
# Return a sub-collection of this collection by name. If 'users' is a collection, then
|
@@ -73,8 +74,14 @@ module Mongo
|
|
73
74
|
# @return [Collection]
|
74
75
|
# the specified sub-collection
|
75
76
|
def [](name)
|
77
|
+
new_name = "#{self.name}.#{name}"
|
78
|
+
validate_name new_name
|
79
|
+
@db.create_collection(new_name, @opts)
|
76
80
|
end
|
77
81
|
|
82
|
+
def capped?
|
83
|
+
@j_collection.isCapped
|
84
|
+
end
|
78
85
|
# Set a hint field for query optimizer. Hint may be a single field
|
79
86
|
# name, array of field names, or a hash (preferably an [OrderedHash]).
|
80
87
|
# If using MongoDB > 1.1, you probably don't ever need to set a hint.
|
@@ -131,29 +138,34 @@ module Mongo
|
|
131
138
|
#
|
132
139
|
# @core find find-instance_method
|
133
140
|
def find(selector={}, opts={})
|
134
|
-
fields = opts.delete(:fields)
|
135
|
-
fields = ["_id"] if fields && fields.empty?
|
141
|
+
fields = prep_fields(opts.delete(:fields))
|
136
142
|
skip = opts.delete(:skip) || skip || 0
|
137
143
|
limit = opts.delete(:limit) || 0
|
138
144
|
sort = opts.delete(:sort)
|
139
145
|
hint = opts.delete(:hint)
|
140
146
|
snapshot = opts.delete(:snapshot)
|
141
147
|
batch_size = opts.delete(:batch_size)
|
142
|
-
|
148
|
+
timeout = (opts.delete(:timeout) == false) ? false : true
|
149
|
+
transformer = opts.delete(:transformer)
|
150
|
+
if timeout == false && !block_given?
|
143
151
|
raise ArgumentError, "Timeout can be set to false only when #find is invoked with a block."
|
144
152
|
end
|
145
|
-
|
153
|
+
|
146
154
|
if hint
|
147
155
|
hint = normalize_hint_fields(hint)
|
148
156
|
else
|
149
157
|
hint = @hint # assumed to be normalized already
|
150
158
|
end
|
159
|
+
|
151
160
|
raise RuntimeError, "Unknown options [#{opts.inspect}]" unless opts.empty?
|
152
161
|
|
153
162
|
cursor = Cursor.new(self, :selector => selector, :fields => fields, :skip => skip, :limit => limit,
|
154
|
-
|
163
|
+
:order => sort, :hint => hint, :snapshot => snapshot,
|
164
|
+
:batch_size => batch_size, :timeout => timeout,
|
165
|
+
:transformer => transformer)
|
155
166
|
if block_given?
|
156
167
|
yield cursor
|
168
|
+
cursor.close
|
157
169
|
nil
|
158
170
|
else
|
159
171
|
cursor
|
@@ -186,7 +198,11 @@ module Mongo
|
|
186
198
|
else
|
187
199
|
raise TypeError, "spec_or_object_id must be an instance of ObjectId or Hash, or nil"
|
188
200
|
end
|
189
|
-
|
201
|
+
begin
|
202
|
+
find_one_document(spec, opts)
|
203
|
+
rescue => ex
|
204
|
+
raise OperationFailure, ex.message
|
205
|
+
end
|
190
206
|
end
|
191
207
|
|
192
208
|
# Save a document to this collection.
|
@@ -225,8 +241,9 @@ module Mongo
|
|
225
241
|
doc_or_docs = [doc_or_docs] unless doc_or_docs.kind_of?(Array)
|
226
242
|
doc_or_docs.collect! { |doc| @pk_factory.create_pk(doc) }
|
227
243
|
safe = (options[:safe] || false)
|
228
|
-
|
229
|
-
|
244
|
+
continue = (options[:continue_on_error] || false)
|
245
|
+
docs = insert_documents(doc_or_docs, safe, continue)
|
246
|
+
docs.size == 1 ? docs.first['_id'] : docs.collect{|doc| doc['_id']}
|
230
247
|
end
|
231
248
|
alias_method :<<, :insert
|
232
249
|
|
@@ -279,7 +296,7 @@ module Mongo
|
|
279
296
|
def update(selector, document, options={})
|
280
297
|
upsert, multi = !!(options[:upsert]), !!(options[:multi])
|
281
298
|
safe = (options[:safe] || false)
|
282
|
-
update_documents(selector, document,upsert,multi,safe)
|
299
|
+
update_documents(selector, document, upsert, multi, safe)
|
283
300
|
end
|
284
301
|
|
285
302
|
# Create a new index.
|
@@ -325,17 +342,21 @@ module Mongo
|
|
325
342
|
#
|
326
343
|
# @core indexes create_index-instance_method
|
327
344
|
def create_index(spec, opts={})
|
328
|
-
|
345
|
+
_create_indexes(spec, opts)
|
329
346
|
end
|
330
347
|
alias_method :ensure_index, :create_index
|
331
348
|
|
332
349
|
# Drop a specified index.
|
333
350
|
#
|
334
|
-
# @param [String]
|
351
|
+
# @param [String, Array] spec
|
352
|
+
# should be either a single field name or an array of
|
353
|
+
# [field name, direction] pairs. Directions should be specified
|
354
|
+
# as Mongo::ASCENDING, Mongo::DESCENDING, or Mongo::GEO2D.
|
335
355
|
#
|
336
356
|
# @core indexes
|
337
|
-
def drop_index(
|
338
|
-
|
357
|
+
def drop_index(spec)
|
358
|
+
raise MongoArgumentError, "Cannot drop index for nil name" unless name
|
359
|
+
_drop_index(spec)
|
339
360
|
end
|
340
361
|
|
341
362
|
# Drop all indexes.
|
@@ -369,12 +390,14 @@ module Mongo
|
|
369
390
|
def find_and_modify(opts={})
|
370
391
|
query = opts[:query] || {}
|
371
392
|
fields = opts[:fields] || {}
|
372
|
-
sort = opts[:sort] ||
|
393
|
+
sort = prep_sort(opts[:sort] || [])
|
373
394
|
update = opts[:update] || {}
|
374
395
|
remove = opts[:remove] || false
|
375
396
|
new_ = opts[:new] || false
|
376
397
|
upsert = opts[:upsert] || false
|
377
|
-
|
398
|
+
trap_raise(OperationFailure) do
|
399
|
+
find_and_modify_document(query, fields, sort, remove, update, new_, upsert)
|
400
|
+
end
|
378
401
|
end
|
379
402
|
|
380
403
|
# Perform a map/reduce operation on the current collection.
|
@@ -399,72 +422,125 @@ module Mongo
|
|
399
422
|
#
|
400
423
|
# @core mapreduce map_reduce-instance_method
|
401
424
|
def map_reduce(map, reduce, opts={})
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
425
|
+
query = opts.fetch(:query,{})
|
426
|
+
sort = opts.fetch(:sort,[])
|
427
|
+
limit = opts.fetch(:limit,0)
|
428
|
+
finalize = opts[:finalize]
|
429
|
+
out = opts[:out]
|
430
|
+
keeptemp = opts.fetch(:keeptemp,true)
|
431
|
+
verbose = opts.fetch(:verbose,true)
|
432
|
+
raw = opts.delete(:raw)
|
433
|
+
|
434
|
+
m = map.to_s
|
435
|
+
r = reduce.to_s
|
436
|
+
|
437
|
+
mrc = case out
|
438
|
+
when String
|
439
|
+
JMongo::MapReduceCommand.new(@j_collection, m, r, out, REPLACE, to_dbobject(query))
|
440
|
+
when Hash
|
441
|
+
if out.keys.size != 1
|
442
|
+
raise ArgumentError, "You need to specify one key value pair in the out hash"
|
443
|
+
end
|
444
|
+
out_type = out.keys.first
|
445
|
+
out_val = out[out_type]
|
446
|
+
unless MapReduceEnumHash.keys.include?(out_type)
|
447
|
+
raise ArgumentError, "Your out hash must have one of these keys: #{MapReduceEnumHash.keys}"
|
448
|
+
end
|
449
|
+
out_type_enum = MapReduceEnumHash[out_type]
|
450
|
+
out_dest = out_val.is_a?(String) ? out_val : nil
|
451
|
+
JMongo::MapReduceCommand.new(@j_collection, m, r, out_dest, out_type_enum, to_dbobject(query))
|
452
|
+
else
|
453
|
+
raise ArgumentError, "You need to specify an out parameter in the options hash"
|
454
|
+
end
|
455
|
+
|
456
|
+
mrc.verbose = verbose
|
457
|
+
mrc.sort = prep_sort(sort)
|
458
|
+
mrc.limit = limit
|
459
|
+
mrc.finalize = finalize
|
460
|
+
result = from_dbobject(@j_db.command(mrc.toDBObject))
|
461
|
+
|
462
|
+
if raw
|
463
|
+
result
|
464
|
+
elsif result["result"]
|
465
|
+
@db[result["result"]]
|
466
|
+
else
|
467
|
+
raise ArgumentError, "Could not instantiate collection from result. If you specified " +
|
468
|
+
"{:out => {:inline => true}}, then you must also specify :raw => true to get the results."
|
414
469
|
end
|
415
|
-
@db[result["result"]]
|
416
470
|
end
|
417
471
|
alias :mapreduce :map_reduce
|
418
472
|
|
419
473
|
# Perform a group aggregation.
|
420
474
|
#
|
421
|
-
# @param [
|
422
|
-
#
|
423
|
-
#
|
424
|
-
# @
|
425
|
-
# @
|
426
|
-
# @
|
427
|
-
#
|
428
|
-
#
|
429
|
-
#
|
430
|
-
# @
|
431
|
-
|
432
|
-
|
475
|
+
# @param [Hash] opts the options for this group operation. The minimum required are :initial
|
476
|
+
# and :reduce.
|
477
|
+
#
|
478
|
+
# @option opts [Array, String, Symbol] :key (nil) Either the name of a field or a list of fields to group by (optional).
|
479
|
+
# @option opts [String, BSON::Code] :keyf (nil) A JavaScript function to be used to generate the grouping keys (optional).
|
480
|
+
# @option opts [String, BSON::Code] :cond ({}) A document specifying a query for filtering the documents over
|
481
|
+
# which the aggregation is run (optional).
|
482
|
+
# @option opts [Hash] :initial the initial value of the aggregation counter object (required).
|
483
|
+
# @option opts [String, BSON::Code] :reduce (nil) a JavaScript aggregation function (required).
|
484
|
+
# @option opts [String, BSON::Code] :finalize (nil) a JavaScript function that receives and modifies
|
485
|
+
# each of the resultant grouped objects. Available only when group is run with command
|
486
|
+
# set to true.
|
487
|
+
#
|
488
|
+
# @return [Array] the command response consisting of grouped items.
|
489
|
+
def group(opts, condition={}, initial={}, reduce=nil, finalize=nil)
|
490
|
+
key = keyf = false
|
491
|
+
if opts.is_a?(Hash)
|
492
|
+
reduce, finalize, initial= opts.values_at(:reduce, :finalize, :initial)
|
493
|
+
key, keyf = opts.values_at(:key, :keyf)
|
494
|
+
condition = opts.fetch(:cond, {})
|
495
|
+
unless key.nil? && keyf.nil?
|
496
|
+
unless key.is_a?(Array) || keyf.is_a?(String) || keyf.is_a?(BSON::Code)
|
497
|
+
raise MongoArgumentError, "Group takes either an array of fields to group by or a JavaScript function" +
|
498
|
+
"in the form of a String or BSON::Code."
|
499
|
+
end
|
500
|
+
end
|
501
|
+
else
|
502
|
+
warn "Collection#group no longer take a list of parameters. This usage is deprecated and will be remove in v2.0." +
|
503
|
+
"Check out the new API at http://api.mongodb.org/ruby/current/Mongo/Collection.html#group-instance_method"
|
504
|
+
case opts
|
505
|
+
when Array
|
506
|
+
key = opts
|
507
|
+
when String, BSON::Code
|
508
|
+
keyf = opts
|
509
|
+
else
|
510
|
+
raise MongoArgumentError, "Group takes either an array of fields to group by or a JavaScript function" +
|
511
|
+
"in the form of a String or BSON::Code."
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
if !(reduce && initial)
|
516
|
+
raise MongoArgumentError, "Group requires at minimum values for initial and reduce."
|
517
|
+
end
|
433
518
|
|
434
|
-
|
519
|
+
cmd = {
|
435
520
|
"group" => {
|
436
521
|
"ns" => @name,
|
437
|
-
"$reduce" => reduce,
|
522
|
+
"$reduce" => reduce.to_bson_code,
|
438
523
|
"cond" => condition,
|
439
524
|
"initial" => initial
|
440
525
|
}
|
441
526
|
}
|
442
527
|
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
else
|
449
|
-
key_type = "$keyf"
|
450
|
-
key_value = key.is_a?(BSON::Code) ? key : BSON::Code.new(key)
|
451
|
-
end
|
452
|
-
|
453
|
-
group_command["group"][key_type] = key_value
|
528
|
+
if keyf
|
529
|
+
cmd["group"]["$keyf"] = keyf.to_bson_code
|
530
|
+
elsif key
|
531
|
+
key_hash = Hash[key.zip( [1]*key.size )]
|
532
|
+
cmd["group"]["key"] = key_hash
|
454
533
|
end
|
455
534
|
|
456
|
-
|
457
|
-
|
458
|
-
group_command['group']['finalize'] = finalize
|
535
|
+
if finalize
|
536
|
+
cmd['group']['finalize'] = finalize.to_bson_code
|
459
537
|
end
|
460
538
|
|
461
|
-
result = @db.command
|
539
|
+
result = from_dbobject(@db.command(cmd))
|
462
540
|
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
raise OperationFailure, "group command failed: #{result['errmsg']}"
|
467
|
-
end
|
541
|
+
return result["retval"] if Mongo.result_ok?(result)
|
542
|
+
|
543
|
+
raise OperationFailure, "group command failed: #{result['errmsg']}"
|
468
544
|
end
|
469
545
|
|
470
546
|
# Return a list of distinct values for +key+ across all
|
@@ -494,12 +570,11 @@ module Mongo
|
|
494
570
|
# @return [Array] an array of distinct values.
|
495
571
|
def distinct(key, query=nil)
|
496
572
|
raise MongoArgumentError unless [String, Symbol].include?(key.class)
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
@db.command(command)["values"]
|
573
|
+
if query
|
574
|
+
from_dbobject @j_collection.distinct(key.to_s, to_dbobject(query))
|
575
|
+
else
|
576
|
+
from_dbobject @j_collection.distinct(key.to_s)
|
577
|
+
end
|
503
578
|
end
|
504
579
|
|
505
580
|
# Rename this collection.
|
@@ -511,25 +586,14 @@ module Mongo
|
|
511
586
|
#
|
512
587
|
# @raise [Mongo::InvalidNSName] if +new_name+ is an invalid collection name.
|
513
588
|
def rename(new_name)
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
589
|
+
name = validate_name(new_name)
|
590
|
+
begin
|
591
|
+
jcol = @j_collection.rename(name)
|
592
|
+
@name = name
|
593
|
+
@j_collection = jcol
|
594
|
+
rescue => ex
|
595
|
+
raise MongoDBError, "Error renaming collection: #{name}, more: #{ex.message}"
|
518
596
|
end
|
519
|
-
|
520
|
-
new_name = new_name.to_s
|
521
|
-
|
522
|
-
if new_name.empty? or new_name.include? ".."
|
523
|
-
raise Mongo::InvalidNSName, "collection names cannot be empty"
|
524
|
-
end
|
525
|
-
if new_name.include? "$"
|
526
|
-
raise Mongo::InvalidNSName, "collection names must not contain '$'"
|
527
|
-
end
|
528
|
-
if new_name.match(/^\./) or new_name.match(/\.$/)
|
529
|
-
raise Mongo::InvalidNSName, "collection names must not start or end with '.'"
|
530
|
-
end
|
531
|
-
|
532
|
-
@db.rename_collection(@name, new_name)
|
533
597
|
end
|
534
598
|
|
535
599
|
# Get information on the indexes for this collection.
|
@@ -546,7 +610,9 @@ module Mongo
|
|
546
610
|
#
|
547
611
|
# @return [Hash] options that apply to this collection.
|
548
612
|
def options
|
549
|
-
@db.collections_info(@name).
|
613
|
+
info = @db.collections_info(@name).to_a
|
614
|
+
ap info
|
615
|
+
info.last['options']
|
550
616
|
end
|
551
617
|
|
552
618
|
# Return stats on the collection. Uses MongoDB's collstats command.
|
@@ -559,14 +625,36 @@ module Mongo
|
|
559
625
|
# Get the number of documents in this collection.
|
560
626
|
#
|
561
627
|
# @return [Integer]
|
562
|
-
def count
|
563
|
-
@j_collection.count()
|
628
|
+
def count(opts={})
|
629
|
+
return @j_collection.count() if opts.empty?
|
630
|
+
query = opts[:query] || opts['query'] || {}
|
631
|
+
fields = opts[:fields] || opts['fields'] || {}
|
632
|
+
limit = opts[:limit] || opts['limit'] || 0
|
633
|
+
skip = opts[:skip] || opts['skip'] || 0
|
634
|
+
@j_collection.get_count(to_dbobject(query), to_dbobject(fields), limit, skip)
|
564
635
|
end
|
565
636
|
|
566
637
|
alias :size :count
|
567
638
|
|
568
639
|
protected
|
569
640
|
|
641
|
+
def validate_name(new_name)
|
642
|
+
raise TypeError, "new_name must be a string like" unless new_name.respond_to?(:to_s)
|
643
|
+
|
644
|
+
name = new_name.to_s
|
645
|
+
|
646
|
+
if name.empty? || name.include?("..")
|
647
|
+
raise Mongo::InvalidNSName, "collection names cannot be empty"
|
648
|
+
end
|
649
|
+
if name.include? "$"
|
650
|
+
raise Mongo::InvalidNSName, "collection names must not contain '$'" unless name =~ /((^\$cmd)|(oplog\.\$main))/
|
651
|
+
end
|
652
|
+
if name.match(/^\./) || name.match(/\.$/)
|
653
|
+
raise Mongo::InvalidNSName, "collection names must not start or end with '.'"
|
654
|
+
end
|
655
|
+
name
|
656
|
+
end
|
657
|
+
|
570
658
|
def normalize_hint_fields(hint)
|
571
659
|
case hint
|
572
660
|
when String
|
@@ -576,16 +664,10 @@ module Mongo
|
|
576
664
|
when nil
|
577
665
|
nil
|
578
666
|
else
|
579
|
-
h = OrderedHash.new
|
580
|
-
hint.to_a.each { |k| h[k] = 1 }
|
667
|
+
h = BSON::OrderedHash.new
|
668
|
+
hint.to_a.each { |k| h[k.to_s] = 1 }
|
581
669
|
h
|
582
670
|
end
|
583
671
|
end
|
584
|
-
|
585
|
-
private
|
586
|
-
|
587
|
-
def generate_index_name(spec)
|
588
|
-
@j_collection.genIndexName(to_dbobject(spec))
|
589
|
-
end
|
590
672
|
end
|
591
673
|
end
|