jmongo 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/Gemfile +8 -0
  2. data/Gemfile.lock +43 -0
  3. data/Rakefile +72 -0
  4. data/jmongo.gemspec +84 -6
  5. data/lib/jmongo.rb +6 -14
  6. data/lib/jmongo/collection.rb +196 -114
  7. data/lib/jmongo/connection.rb +39 -13
  8. data/lib/jmongo/cursor.rb +161 -63
  9. data/lib/jmongo/db.rb +119 -30
  10. data/lib/jmongo/exceptions.rb +39 -0
  11. data/lib/jmongo/mongo-2.6.5.gb1.jar +0 -0
  12. data/lib/jmongo/mongo/bson.rb +130 -0
  13. data/lib/jmongo/mongo/collection.rb +185 -0
  14. data/lib/jmongo/mongo/connection.rb +45 -0
  15. data/lib/jmongo/mongo/db.rb +31 -0
  16. data/lib/jmongo/mongo/jmongo.rb +44 -0
  17. data/lib/jmongo/mongo/mongo.rb +98 -0
  18. data/lib/jmongo/mongo/ruby_ext.rb +38 -0
  19. data/lib/jmongo/mongo/utils.rb +136 -0
  20. data/lib/jmongo/version.rb +1 -1
  21. data/test-results.txt +98 -0
  22. data/test/auxillary/1.4_features.rb +166 -0
  23. data/test/auxillary/authentication_test.rb +68 -0
  24. data/test/auxillary/autoreconnect_test.rb +41 -0
  25. data/test/auxillary/fork_test.rb +30 -0
  26. data/test/auxillary/repl_set_auth_test.rb +58 -0
  27. data/test/auxillary/slave_connection_test.rb +36 -0
  28. data/test/auxillary/threaded_authentication_test.rb +101 -0
  29. data/test/bson/binary_test.rb +15 -0
  30. data/test/bson/bson_test.rb +657 -0
  31. data/test/bson/byte_buffer_test.rb +208 -0
  32. data/test/bson/hash_with_indifferent_access_test.rb +38 -0
  33. data/test/bson/json_test.rb +17 -0
  34. data/test/bson/object_id_test.rb +138 -0
  35. data/test/bson/ordered_hash_test.rb +245 -0
  36. data/test/bson/test_helper.rb +46 -0
  37. data/test/bson/timestamp_test.rb +46 -0
  38. data/test/collection_test.rb +933 -0
  39. data/test/connection_test.rb +325 -0
  40. data/test/conversions_test.rb +121 -0
  41. data/test/cursor_fail_test.rb +75 -0
  42. data/test/cursor_message_test.rb +43 -0
  43. data/test/cursor_test.rb +547 -0
  44. data/test/data/empty_data +0 -0
  45. data/test/data/sample_data +0 -0
  46. data/test/data/sample_file.pdf +0 -0
  47. data/test/data/small_data.txt +1 -0
  48. data/test/db_api_test.rb +739 -0
  49. data/test/db_connection_test.rb +15 -0
  50. data/test/db_test.rb +325 -0
  51. data/test/grid_file_system_test.rb +260 -0
  52. data/test/grid_io_test.rb +210 -0
  53. data/test/grid_test.rb +259 -0
  54. data/test/load/thin/config.ru +6 -0
  55. data/test/load/thin/config.yml.template +6 -0
  56. data/test/load/thin/load.rb +24 -0
  57. data/test/load/unicorn/config.ru +6 -0
  58. data/test/load/unicorn/load.rb +23 -0
  59. data/test/load/unicorn/unicorn.rb.template +29 -0
  60. data/test/replica_sets/connect_test.rb +111 -0
  61. data/test/replica_sets/connection_string_test.rb +29 -0
  62. data/test/replica_sets/count_test.rb +36 -0
  63. data/test/replica_sets/insert_test.rb +54 -0
  64. data/test/replica_sets/pooled_insert_test.rb +58 -0
  65. data/test/replica_sets/query_secondaries.rb +109 -0
  66. data/test/replica_sets/query_test.rb +52 -0
  67. data/test/replica_sets/read_preference_test.rb +43 -0
  68. data/test/replica_sets/refresh_test.rb +123 -0
  69. data/test/replica_sets/replication_ack_test.rb +71 -0
  70. data/test/replica_sets/rs_test_helper.rb +27 -0
  71. data/test/safe_test.rb +68 -0
  72. data/test/support/hash_with_indifferent_access.rb +186 -0
  73. data/test/support/keys.rb +45 -0
  74. data/test/support_test.rb +19 -0
  75. data/test/test_helper.rb +111 -0
  76. data/test/threading/threading_with_large_pool_test.rb +90 -0
  77. data/test/threading_test.rb +88 -0
  78. data/test/tools/auth_repl_set_manager.rb +14 -0
  79. data/test/tools/keyfile.txt +1 -0
  80. data/test/tools/repl_set_manager.rb +377 -0
  81. data/test/unit/collection_test.rb +128 -0
  82. data/test/unit/connection_test.rb +85 -0
  83. data/test/unit/cursor_test.rb +127 -0
  84. data/test/unit/db_test.rb +96 -0
  85. data/test/unit/grid_test.rb +51 -0
  86. data/test/unit/node_test.rb +73 -0
  87. data/test/unit/pool_manager_test.rb +47 -0
  88. data/test/unit/pool_test.rb +9 -0
  89. data/test/unit/read_test.rb +101 -0
  90. data/test/unit/safe_test.rb +125 -0
  91. data/test/uri_test.rb +92 -0
  92. metadata +170 -99
  93. data/lib/jmongo/ajrb.rb +0 -189
  94. data/lib/jmongo/jmongo_jext.rb +0 -302
  95. data/lib/jmongo/mongo-2.6.3.jar +0 -0
  96. 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
@@ -1,3 +1,3 @@
1
1
  module Mongo
2
- VERSION = '1.0.3'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -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