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
@@ -0,0 +1,98 @@
|
|
1
|
+
module Mongo
|
2
|
+
ASCENDING = 1
|
3
|
+
DESCENDING = -1
|
4
|
+
GEO2D = '2d'
|
5
|
+
|
6
|
+
DEFAULT_MAX_BSON_SIZE = 1024 * 1024 * 4
|
7
|
+
|
8
|
+
REPLACE = JMongo::MapReduceCommand::OutputType::REPLACE
|
9
|
+
MERGE = JMongo::MapReduceCommand::OutputType::MERGE
|
10
|
+
REDUCE = JMongo::MapReduceCommand::OutputType::REDUCE
|
11
|
+
INLINE = JMongo::MapReduceCommand::OutputType::INLINE
|
12
|
+
|
13
|
+
MapReduceEnumHash = {:replace => REPLACE, :merge => MERGE, :reduce => REDUCE, :inline => INLINE}
|
14
|
+
|
15
|
+
DEFAULT_BATCH_SIZE = 100
|
16
|
+
|
17
|
+
OP_REPLY = 1
|
18
|
+
OP_MSG = 1000
|
19
|
+
OP_UPDATE = 2001
|
20
|
+
OP_INSERT = 2002
|
21
|
+
OP_QUERY = 2004
|
22
|
+
OP_GET_MORE = 2005
|
23
|
+
OP_DELETE = 2006
|
24
|
+
OP_KILL_CURSORS = 2007
|
25
|
+
|
26
|
+
OP_QUERY_TAILABLE = JMongo::Bytes::QUERYOPTION_TAILABLE
|
27
|
+
OP_QUERY_SLAVE_OK = JMongo::Bytes::QUERYOPTION_SLAVEOK
|
28
|
+
OP_QUERY_OPLOG_REPLAY = JMongo::Bytes::QUERYOPTION_OPLOGREPLAY
|
29
|
+
OP_QUERY_NO_CURSOR_TIMEOUT = JMongo::Bytes::QUERYOPTION_NOTIMEOUT
|
30
|
+
OP_QUERY_AWAIT_DATA = JMongo::Bytes::QUERYOPTION_AWAITDATA
|
31
|
+
OP_QUERY_EXHAUST = JMongo::Bytes::QUERYOPTION_EXHAUST
|
32
|
+
|
33
|
+
REPLY_CURSOR_NOT_FOUND = JMongo::Bytes::RESULTFLAG_CURSORNOTFOUND
|
34
|
+
REPLY_QUERY_FAILURE = JMongo::Bytes::RESULTFLAG_ERRSET
|
35
|
+
REPLY_SHARD_CONFIG_STALE = JMongo::Bytes::RESULTFLAG_SHARDCONFIGSTALE
|
36
|
+
REPLY_AWAIT_CAPABLE = JMongo::Bytes::RESULTFLAG_AWAITCAPABLE
|
37
|
+
|
38
|
+
def self.logger(logger=nil)
|
39
|
+
logger ? @logger = logger : @logger
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.result_ok?(result)
|
43
|
+
result['ok'] == 1.0 || result['ok'] == true
|
44
|
+
end
|
45
|
+
|
46
|
+
# Simple class for comparing server versions.
|
47
|
+
class ServerVersion
|
48
|
+
include Comparable
|
49
|
+
|
50
|
+
def initialize(version)
|
51
|
+
@version = version
|
52
|
+
end
|
53
|
+
|
54
|
+
# Implements comparable.
|
55
|
+
def <=>(new)
|
56
|
+
local, new = self.to_a, to_array(new)
|
57
|
+
for n in 0...local.size do
|
58
|
+
break if elements_include_mods?(local[n], new[n])
|
59
|
+
if local[n] < new[n].to_i
|
60
|
+
result = -1
|
61
|
+
break;
|
62
|
+
elsif local[n] > new[n].to_i
|
63
|
+
result = 1
|
64
|
+
break;
|
65
|
+
end
|
66
|
+
end
|
67
|
+
result || 0
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return an array representation of this server version.
|
71
|
+
def to_a
|
72
|
+
to_array(@version)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Return a string representation of this server version.
|
76
|
+
def to_s
|
77
|
+
@version
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# Returns true if any elements include mod symbols (-, +)
|
83
|
+
def elements_include_mods?(*elements)
|
84
|
+
elements.any? { |n| n =~ /[\-\+]/ }
|
85
|
+
end
|
86
|
+
|
87
|
+
# Converts argument to an array of integers,
|
88
|
+
# appending any mods as the final element.
|
89
|
+
def to_array(version)
|
90
|
+
array = version.split(".").map {|n| (n =~ /^\d+$/) ? n.to_i : n }
|
91
|
+
if array.last =~ /(\d+)([\-\+])/
|
92
|
+
array[array.length-1] = $1.to_i
|
93
|
+
array << $2
|
94
|
+
end
|
95
|
+
array
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
class String
|
3
|
+
def to_bson_code
|
4
|
+
BSON::Code.new(self)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class Symbol
|
9
|
+
def to_bson
|
10
|
+
BSON::Symbol.new(self.to_s)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Object
|
15
|
+
def to_bson
|
16
|
+
self
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Hash
|
21
|
+
def to_bson
|
22
|
+
obj = ::JMongo::BasicDBObject.new
|
23
|
+
self.each_pair do |key, val|
|
24
|
+
obj.put( key.to_s, val.to_bson )
|
25
|
+
end
|
26
|
+
obj
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Array
|
31
|
+
def to_bson
|
32
|
+
list = Array.new #Java::ComMongodb::DBObject[ary.length].new
|
33
|
+
self.each_with_index do |ele, i|
|
34
|
+
list[i] = ele.to_bson
|
35
|
+
end
|
36
|
+
list
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# Copyright (C) 2010 Guy Boertje
|
2
|
+
|
3
|
+
module Mongo
|
4
|
+
module JavaImpl
|
5
|
+
|
6
|
+
module NoImplYetClass
|
7
|
+
def raise_not_implemented
|
8
|
+
raise NoMethodError, "This method hasn't been implemented yet."
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Utils
|
13
|
+
def raise_not_implemented
|
14
|
+
raise NoMethodError, "This method hasn't been implemented yet."
|
15
|
+
end
|
16
|
+
|
17
|
+
def trap_raise(ex_class, msg=nil)
|
18
|
+
begin
|
19
|
+
yield
|
20
|
+
rescue => ex
|
21
|
+
raise ex_class, msg ? "#{msg} - #{ex.message}" : ex.message
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def prep_fields(fields)
|
26
|
+
case fields
|
27
|
+
when String, Symbol
|
28
|
+
{fields => 1}
|
29
|
+
when Array
|
30
|
+
fields << "_id" if fields.empty?
|
31
|
+
Hash[fields.zip( [1]*fields.size )]
|
32
|
+
when Hash
|
33
|
+
fields
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def prep_sort(key_or_list=nil, direction=nil)
|
38
|
+
return if key_or_list.nil?
|
39
|
+
if !direction.nil?
|
40
|
+
order = [[key_or_list, direction]]
|
41
|
+
elsif key_or_list.is_a?(String) || key_or_list.is_a?(Symbol)
|
42
|
+
order = [[key_or_list.to_s, 1]]
|
43
|
+
else
|
44
|
+
order = [key_or_list]
|
45
|
+
end
|
46
|
+
hord = {}
|
47
|
+
order.flatten.each_slice(2){|k,v| hord[k] = sort_value(k,v)}
|
48
|
+
to_dbobject(hord)
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_dbobject obj
|
52
|
+
if obj.respond_to?('to_bson')
|
53
|
+
obj.to_bson
|
54
|
+
elsif obj.respond_to?(:merge)
|
55
|
+
hash_to_dbobject(obj)
|
56
|
+
elsif obj.respond_to?(:compact)
|
57
|
+
array_to_dblist(obj)
|
58
|
+
else
|
59
|
+
obj
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def from_dbobject obj
|
64
|
+
# for better upstream compatibility make the objects into ruby hash or array
|
65
|
+
|
66
|
+
case obj
|
67
|
+
when Java::ComMongodb::BasicDBObject, Java::ComMongodb::CommandResult
|
68
|
+
h = obj.hashify
|
69
|
+
Hash[h.keys.zip(h.values.map{|v| from_dbobject(v)})]
|
70
|
+
when Java::ComMongodb::BasicDBList
|
71
|
+
obj.arrayify.map{|v| from_dbobject(v)}
|
72
|
+
when Java::JavaUtil::ArrayList
|
73
|
+
obj.map{|v| from_dbobject(v)}
|
74
|
+
when Java::JavaUtil::Date
|
75
|
+
Time.at(obj.get_time/1000.0)
|
76
|
+
when Java::OrgBsonTypes::Symbol
|
77
|
+
obj.toString.to_sym
|
78
|
+
else
|
79
|
+
obj
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def sort_value(key, value)
|
84
|
+
val = value.to_s.downcase
|
85
|
+
return val if val == '2d'
|
86
|
+
direction = SortingHash[val]
|
87
|
+
return direction if direction != 0
|
88
|
+
raise InvalidSortValueError.new(
|
89
|
+
"for key: #{key}, #{value} was supplied as a sort direction when acceptable values are: " +
|
90
|
+
"Mongo::ASCENDING, 'ascending', 'asc', :ascending, :asc, 1, Mongo::DESCENDING, " +
|
91
|
+
"'descending', 'desc', :descending, :desc, -1.")
|
92
|
+
end
|
93
|
+
|
94
|
+
SortingHash = Hash.new(0).merge!(
|
95
|
+
"ascending" => 1, "asc" => 1, "1" => 1,
|
96
|
+
"descending" => -1, "desc" => -1, "-1" => -1
|
97
|
+
)
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def hash_to_dbobject doc
|
102
|
+
obj = JMongo::BasicDBObject.new
|
103
|
+
doc.each_pair do |key, value|
|
104
|
+
obj.put(key.to_s, to_dbobject(value))
|
105
|
+
end
|
106
|
+
obj
|
107
|
+
end
|
108
|
+
|
109
|
+
def array_to_dblist ary
|
110
|
+
list = [] #Java::ComMongodb::DBObject[ary.length].new
|
111
|
+
ary.each_with_index do |ele, i|
|
112
|
+
list[i] = to_dbobject(ele)
|
113
|
+
end
|
114
|
+
list
|
115
|
+
end
|
116
|
+
|
117
|
+
#@collection.save({:doc => 'foo'}, :safe => nil) ---> NONE = new WriteConcern(-1)
|
118
|
+
#@collection.save({:doc => 'foo'}, :safe => true) ---> NORMAL = new WriteConcern(0)
|
119
|
+
#@collection.save({:doc => 'foo'}, :safe => {:w => 2}) ---> new WriteConcern( 2 , 0 , false)
|
120
|
+
#@collection.save({:doc => 'foo'}, :safe => {:w => 2, :wtimeout => 200}) ---> new WriteConcern( 2 , 200 , false)
|
121
|
+
#@collection.save({:doc => 'foo'}, :safe => {:w => 2, :wtimeout => 200, :fsync => true}) ---> new WriteConcern( 2 , 0 , true)
|
122
|
+
#@collection.save({:doc => 'foo'}, :safe => {:fsync => true}) ---> FSYNC_SAFE = new WriteConcern( 1 , 0 , true)
|
123
|
+
|
124
|
+
def write_concern(safe)
|
125
|
+
return JMongo::WriteConcern.new(-1) if safe.nil?
|
126
|
+
return JMongo::WriteConcern.new(0) if safe.is_a?(FalseClass)
|
127
|
+
return JMongo::WriteConcern.new(1) if safe.is_a?(TrueClass)
|
128
|
+
return JMongo::WriteConcern.new(0) unless safe.is_a?(Hash)
|
129
|
+
w = safe[:w] || 1
|
130
|
+
t = safe[:wtimeout] || 0
|
131
|
+
f = !!(safe[:fsync] || false)
|
132
|
+
JMongo::WriteConcern.new(w, t, f) #dont laugh!
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
data/lib/jmongo/version.rb
CHANGED
data/test-results.txt
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
Loaded suite ./test/collection_test
|
2
|
+
Started
|
3
|
+
"test_map_reduce_with_raw_response"
|
4
|
+
"function() { emit(this.user_id, 1); }"
|
5
|
+
"function(k,vals) { return 1; }"
|
6
|
+
{
|
7
|
+
"result" => "foo",
|
8
|
+
"timeMillis" => 18,
|
9
|
+
"timing" => {
|
10
|
+
"mapTime" => 0,
|
11
|
+
"emitLoop" => 17,
|
12
|
+
"total" => 18
|
13
|
+
},
|
14
|
+
"counts" => {
|
15
|
+
"input" => 3,
|
16
|
+
"emit" => 3,
|
17
|
+
"output" => 3
|
18
|
+
},
|
19
|
+
"ok" => 1.0
|
20
|
+
}
|
21
|
+
........."test_map_reduce_with_output_collection"
|
22
|
+
"function() { emit(this.user_id, 1); }"
|
23
|
+
"function(k,vals) { return 1; }"
|
24
|
+
{
|
25
|
+
"result" => "test-map-coll",
|
26
|
+
"timeMillis" => 1,
|
27
|
+
"timing" => {
|
28
|
+
"mapTime" => 0,
|
29
|
+
"emitLoop" => 0,
|
30
|
+
"total" => 1
|
31
|
+
},
|
32
|
+
"counts" => {
|
33
|
+
"input" => 3,
|
34
|
+
"emit" => 3,
|
35
|
+
"output" => 3
|
36
|
+
},
|
37
|
+
"ok" => 1.0
|
38
|
+
}
|
39
|
+
....."test_map_reduce_with_code_objects"
|
40
|
+
"function() { emit(this.user_id, 1); }"
|
41
|
+
"function(k,vals) { return 1; }"
|
42
|
+
{
|
43
|
+
"result" => "foo",
|
44
|
+
"timeMillis" => 1,
|
45
|
+
"timing" => {
|
46
|
+
"mapTime" => 0,
|
47
|
+
"emitLoop" => 0,
|
48
|
+
"total" => 1
|
49
|
+
},
|
50
|
+
"counts" => {
|
51
|
+
"input" => 2,
|
52
|
+
"emit" => 2,
|
53
|
+
"output" => 2
|
54
|
+
},
|
55
|
+
"ok" => 1.0
|
56
|
+
}
|
57
|
+
..."test_map_reduce_with_options"
|
58
|
+
"function() { emit(this.user_id, 1); }"
|
59
|
+
"function(k,vals) { return 1; }"
|
60
|
+
{
|
61
|
+
"result" => "foo",
|
62
|
+
"timeMillis" => 1,
|
63
|
+
"timing" => {
|
64
|
+
"mapTime" => 0,
|
65
|
+
"emitLoop" => 0,
|
66
|
+
"total" => 1
|
67
|
+
},
|
68
|
+
"counts" => {
|
69
|
+
"input" => 2,
|
70
|
+
"emit" => 2,
|
71
|
+
"output" => 2
|
72
|
+
},
|
73
|
+
"ok" => 1.0
|
74
|
+
}
|
75
|
+
.."test_map_reduce"
|
76
|
+
"function() { emit(this.user_id, 1); }"
|
77
|
+
"function(k,vals) { return 1; }"
|
78
|
+
{
|
79
|
+
"result" => "foo",
|
80
|
+
"timeMillis" => 1,
|
81
|
+
"timing" => {
|
82
|
+
"mapTime" => 0,
|
83
|
+
"emitLoop" => 0,
|
84
|
+
"total" => 1
|
85
|
+
},
|
86
|
+
"counts" => {
|
87
|
+
"input" => 2,
|
88
|
+
"emit" => 2,
|
89
|
+
"output" => 2
|
90
|
+
},
|
91
|
+
"ok" => 1.0
|
92
|
+
}
|
93
|
+
..............
|
94
|
+
Finished in 0.304000 seconds.
|
95
|
+
|
96
|
+
33 tests, 94 assertions, 0 failures, 0 errors, 0 skips
|
97
|
+
|
98
|
+
Test run options: --seed 45344
|
@@ -0,0 +1,166 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'mongo'
|
3
|
+
require 'test/unit'
|
4
|
+
require './test/test_helper'
|
5
|
+
|
6
|
+
# Demonstrate features in MongoDB 1.4
|
7
|
+
class Features14Test < Test::Unit::TestCase
|
8
|
+
|
9
|
+
context "MongoDB 1.4" do
|
10
|
+
setup do
|
11
|
+
@con = Mongo::Connection.new
|
12
|
+
@db = @con['mongo-ruby-test']
|
13
|
+
@col = @db['new-features']
|
14
|
+
end
|
15
|
+
|
16
|
+
teardown do
|
17
|
+
@col.drop
|
18
|
+
end
|
19
|
+
|
20
|
+
context "new query operators: " do
|
21
|
+
|
22
|
+
context "$elemMatch: " do
|
23
|
+
setup do
|
24
|
+
@col.save({:user => 'bob', :updates => [{:date => Time.now.utc, :body => 'skiing', :n => 1},
|
25
|
+
{:date => Time.now.utc, :body => 'biking', :n => 2}]})
|
26
|
+
|
27
|
+
@col.save({:user => 'joe', :updates => [{:date => Time.now.utc, :body => 'skiing', :n => 2},
|
28
|
+
{:date => Time.now.utc, :body => 'biking', :n => 10}]})
|
29
|
+
end
|
30
|
+
|
31
|
+
should "match a document with a matching object element in an array" do
|
32
|
+
doc = @col.find_one({"updates" => {"$elemMatch" => {"body" => "skiing", "n" => 2}}})
|
33
|
+
assert_equal 'joe', doc['user']
|
34
|
+
end
|
35
|
+
|
36
|
+
should "$elemMatch with a conditional operator" do
|
37
|
+
doc1 = @col.find_one({"updates" => {"$elemMatch" => {"body" => "biking", "n" => {"$gt" => 5}}}})
|
38
|
+
assert_equal 'joe', doc1['user']
|
39
|
+
end
|
40
|
+
|
41
|
+
should "note the difference between $elemMatch and a traditional match" do
|
42
|
+
doc = @col.find({"updates.body" => "skiing", "updates.n" => 2}).to_a
|
43
|
+
assert_equal 2, doc.size
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "$all with regexes" do
|
48
|
+
setup do
|
49
|
+
@col.save({:n => 1, :a => 'whale'})
|
50
|
+
@col.save({:n => 2, :a => 'snake'})
|
51
|
+
end
|
52
|
+
|
53
|
+
should "match multiple regexes" do
|
54
|
+
doc = @col.find({:a => {'$all' => [/ha/, /le/]}}).to_a
|
55
|
+
assert_equal 1, doc.size
|
56
|
+
assert_equal 1, doc.first['n']
|
57
|
+
end
|
58
|
+
|
59
|
+
should "not match if not every regex matches" do
|
60
|
+
doc = @col.find({:a => {'$all' => [/ha/, /sn/]}}).to_a
|
61
|
+
assert_equal 0, doc.size
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "the $not operator" do
|
66
|
+
setup do
|
67
|
+
@col.save({:a => ['x']})
|
68
|
+
@col.save({:a => ['x', 'y']})
|
69
|
+
@col.save({:a => ['x', 'y', 'z']})
|
70
|
+
end
|
71
|
+
|
72
|
+
should "negate a standard operator" do
|
73
|
+
results = @col.find({:a => {'$not' => {'$size' => 2}}}).to_a
|
74
|
+
assert_equal 2, results.size
|
75
|
+
results = results.map {|r| r['a']}
|
76
|
+
assert_equal ['x'], results.sort.first
|
77
|
+
assert_equal ['x', 'y', 'z'], results.sort.last
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "new update operators: " do
|
83
|
+
|
84
|
+
context "$addToSet (pushing a unique value)" do
|
85
|
+
setup do
|
86
|
+
@col.save({:username => 'bob', :interests => ['skiing', 'guitar']})
|
87
|
+
end
|
88
|
+
|
89
|
+
should "add an item to a set uniquely ($addToSet)" do
|
90
|
+
@col.update({:username => 'bob'}, {'$addToSet' => {'interests' => 'skiing'}})
|
91
|
+
@col.update({:username => 'bob'}, {'$addToSet' => {'interests' => 'kayaking'}})
|
92
|
+
document = @col.find_one({:username => 'bob'})
|
93
|
+
assert_equal ['guitar', 'kayaking', 'skiing'], document['interests'].sort
|
94
|
+
end
|
95
|
+
|
96
|
+
should "add an array of items uniquely ($addToSet with $each)" do
|
97
|
+
@col.update({:username => 'bob'}, {'$addToSet' => {'interests' => {'$each' => ['skiing', 'kayaking', 'biking']}}})
|
98
|
+
document = @col.find_one({:username => 'bob'})
|
99
|
+
assert_equal ['biking', 'guitar', 'kayaking', 'skiing'], document['interests'].sort
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "the positional operator ($)" do
|
104
|
+
setup do
|
105
|
+
@id1 = @col.insert({:text => 'hello',
|
106
|
+
:comments => [{'by' => 'bob',
|
107
|
+
'text' => 'lol!'},
|
108
|
+
{'by' => 'susie',
|
109
|
+
'text' => 'bye bye!'}]})
|
110
|
+
@id2 = @col.insert({:text => 'goodbye',
|
111
|
+
:comments => [{'by' => 'bob',
|
112
|
+
'text' => 'au revoir'},
|
113
|
+
{'by' => 'susie',
|
114
|
+
'text' => 'bye bye!'}]})
|
115
|
+
end
|
116
|
+
|
117
|
+
should "update a matching array item" do
|
118
|
+
@col.update({"_id" => @id1, "comments.by" => 'bob'}, {'$set' => {'comments.$.text' => 'lmao!'}}, :multi => true)
|
119
|
+
result = @col.find_one({"_id" => @id1})
|
120
|
+
assert_equal 'lmao!', result['comments'][0]['text']
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "Geoindexing" do
|
126
|
+
setup do
|
127
|
+
@places = @db['places']
|
128
|
+
@places.create_index([['loc', Mongo::GEO2D]])
|
129
|
+
|
130
|
+
@empire_state = ([40.748371, -73.985031])
|
131
|
+
@jfk = ([40.643711, -73.790009])
|
132
|
+
|
133
|
+
@places.insert({'name' => 'Empire State Building', 'loc' => ([40.748371, -73.985031])})
|
134
|
+
@places.insert({'name' => 'Flatiron Building', 'loc' => ([40.741581, -73.987549])})
|
135
|
+
@places.insert({'name' => 'Grand Central', 'loc' => ([40.751678, -73.976562])})
|
136
|
+
@places.insert({'name' => 'Columbia University', 'loc' => ([40.808922, -73.961617])})
|
137
|
+
@places.insert({'name' => 'NYSE', 'loc' => ([40.71455, -74.007124])})
|
138
|
+
@places.insert({'name' => 'JFK', 'loc' => ([40.643711, -73.790009])})
|
139
|
+
end
|
140
|
+
|
141
|
+
teardown do
|
142
|
+
@places.drop
|
143
|
+
end
|
144
|
+
|
145
|
+
should "find the nearest addresses" do
|
146
|
+
results = @places.find({'loc' => {'$near' => @empire_state}}).limit(2).to_a
|
147
|
+
assert_equal 2, results.size
|
148
|
+
assert_equal 'Empire State Building', results[0]['name']
|
149
|
+
assert_equal 'Flatiron Building', results[1]['name']
|
150
|
+
end
|
151
|
+
|
152
|
+
should "use geoNear command to return distances from a point" do
|
153
|
+
cmd = BSON::OrderedHash.new
|
154
|
+
cmd['geoNear'] = 'places'
|
155
|
+
cmd['near'] = @empire_state
|
156
|
+
cmd['num'] = 6
|
157
|
+
r = @db.command(cmd)
|
158
|
+
|
159
|
+
assert_equal 6, r['results'].length
|
160
|
+
r['results'].each do |result|
|
161
|
+
puts result.inspect
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|