mongo 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -5,10 +5,14 @@ This is the 10gen-supported Ruby driver for [MongoDB](http://www.mongodb.org).
5
5
  This documentation includes other articles of interest, include:
6
6
 
7
7
  1. [A tutorial](http://api.mongodb.org/ruby/current/file.TUTORIAL.html).
8
- 2. [History](http://api.mongodb.org/ruby/current/file.HISTORY.html).
9
- 3. [Credits](http://api.mongodb.org/ruby/current/file.CREDITS.html).
10
-
11
- Here's a quick code sample. Again, see the [MongoDB Ruby Tutorial](http://api.mongodb.org/ruby/current/file.TUTORIAL.html)
8
+ 2. [Replica Sets in Ruby](http://api.mongodb.org/ruby/current/file.REPLICA_SETS.html).
9
+ 3. [Write Concern in Ruby](http://api.mongodb.org/ruby/current/file.WRITE_CONCERN.html).
10
+ 4. [GridFS in Ruby](http://api.mongodb.org/ruby/current/file.GridFS.html).
11
+ 5. [Frequently Asked Questions](http://api.mongodb.org/ruby/current/file.FAQ.html).
12
+ 6. [History](http://api.mongodb.org/ruby/current/file.HISTORY.html).
13
+ 7. [Credits](http://api.mongodb.org/ruby/current/file.CREDITS.html).
14
+
15
+ Here's a quick code sample. Again, see the [MongoDB Ruby Tutorial](file.TUTORIAL.html)
12
16
  for much more:
13
17
 
14
18
  require 'rubygems'
data/Rakefile CHANGED
@@ -161,7 +161,7 @@ task :rdoc do
161
161
  version = eval(File.read("mongo.gemspec")).version
162
162
  out = File.join('html', version.to_s)
163
163
  FileUtils.rm_rf('html')
164
- system "rdoc --main README.rdoc --op #{out} --inline-source --quiet README.rdoc `find lib -name '*.rb'`"
164
+ system "rdoc --main README.md --op #{out} --inline-source --quiet README.md `find lib -name '*.rb'`"
165
165
  end
166
166
 
167
167
  desc "Generate YARD documentation"
@@ -169,7 +169,7 @@ task :ydoc do
169
169
  require File.join(File.dirname(__FILE__), 'lib', 'mongo')
170
170
  out = File.join('ydoc', Mongo::VERSION)
171
171
  FileUtils.rm_rf('ydoc')
172
- system "yardoc lib/**/*.rb lib/mongo/**/*.rb lib/bson/**/*.rb -e yard/yard_ext.rb -p yard/templates -o #{out} --title MongoRuby-#{Mongo::VERSION} --files docs/TUTORIAL.md,docs/HISTORY.md,docs/CREDITS.md,docs/1.0_UPGRADE.md"
172
+ system "yardoc lib/**/*.rb lib/mongo/**/*.rb lib/bson/**/*.rb -e yard/yard_ext.rb -p yard/templates -o #{out} --title MongoRuby-#{Mongo::VERSION} --files docs/TUTORIAL.md,docs/GridFS.md,docs/FAQ.md,docs/REPLICA_SETS.md,docs/WRITE_CONCERN.md,docs/HISTORY.md,docs/CREDITS.md,docs/1.0_UPGRADE.md"
173
173
  end
174
174
 
175
175
  namespace :gem do
@@ -0,0 +1,112 @@
1
+ # Ruby MongoDB FAQ
2
+
3
+ This is a list of frequently asked questions about using Ruby with MongoDB. If you have a question you'd like to have answered here, please post your question to the [mongodb-user list](http://groups.google.com/group/mongodb-user).
4
+
5
+ #### Can I run (insert command name here) from the Ruby driver?
6
+
7
+ Yes. You can run any of the [available database commands|List of Database Commands] from the driver using the DB#command method. The only trick is to use an OrderedHash when specifying the command. For example, here's how you'd run an asynchronous fsync from the driver:
8
+
9
+
10
+ # This command is run on the admin database.
11
+ @db = Mongo::Connection.new.db('admin')
12
+
13
+ # Build the command.
14
+ cmd = OrderedHash.new
15
+ cmd['fsync'] = 1
16
+ cmd['async'] = true
17
+
18
+ # Run it.
19
+ @db.command(cmd)
20
+
21
+
22
+ It's important to keep in mind that some commands, like `fsync`, must be run on the `admin` database, while other commands can be run on any database. If you're having trouble, check the [command reference|List of Database Commands] to make sure you're using the command correctly.
23
+
24
+ #### Does the Ruby driver support an EXPLAIN command?
25
+
26
+ Yes. `explain` is, technically speaking, an option sent to a query that tells MongoDB to return an explain plan rather than the query's results. You can use `explain` by constructing a query and calling explain at the end:
27
+
28
+
29
+ @collection = @db['users']
30
+ result = @collection.find({:name => "jones"}).explain
31
+
32
+
33
+ The resulting explain plan might look something like this:
34
+
35
+
36
+ {"cursor"=>"BtreeCursor name_1",
37
+ "startKey"=>{"name"=>"Jones"},
38
+ "endKey"=>{"name"=>"Jones"},
39
+ "nscanned"=>1.0,
40
+ "n"=>1,
41
+ "millis"=>0,
42
+ "oldPlan"=>{"cursor"=>"BtreeCursor name_1",
43
+ "startKey"=>{"name"=>"Jones"},
44
+ "endKey"=>{"name"=>"Jones"}
45
+ },
46
+ "allPlans"=>[{"cursor"=>"BtreeCursor name_1",
47
+ "startKey"=>{"name"=>"Jones"},
48
+ "endKey"=>{"name"=>"Jones"`]
49
+ }
50
+
51
+
52
+ Because this collection has an index on the "name" field, the query uses that index, only having to scan a single record. "n" is the number of records the query will return. "millis" is the time the query takes, in milliseconds. "oldPlan" indicates that the query optimizer has already seen this kind of query and has, therefore, saved an efficient query plan. "allPlans" shows all the plans considered for this query.
53
+
54
+ #### I see that BSON supports a symbol type. Does this mean that I can store Ruby symbols in MongoDB?
55
+
56
+ You can store Ruby symbols in MongoDB, but only as values. BSON specifies that document keys must be strings. So, for instance, you can do this:
57
+
58
+
59
+ @collection = @db['test']
60
+
61
+ boat_id = @collection.save({:vehicle => :boat})
62
+ car_id = @collection.save({"vehicle" => "car"})
63
+
64
+ @collection.find_one('_id' => boat_id)
65
+ {"_id" => ObjectID('4bb372a8238d3b5c8c000001'), "vehicle" => :boat}
66
+
67
+
68
+ @collection.find_one('_id' => car_id)
69
+ {"_id" => ObjectID('4bb372a8238d3b5c8c000002'), "vehicle" => "car"}
70
+
71
+
72
+ Notice that the symbol values are returned as expected, but that symbol keys are treated as strings.
73
+
74
+ #### Why can't I access random elements within a cursor?
75
+
76
+ MongoDB cursors are designed for sequentially iterating over a result set, and all the drivers, including the Ruby driver, stick closely to this directive. Internally, a Ruby cursor fetches results in batches by running a MongoDB `getmore` operation. The results are buffered for efficient iteration on the client-side.
77
+
78
+ What this means is that a cursor is nothing more than a device for returning a result set on a query that's been initiated on the server. Cursors are not containers for result sets. If we allow a cursor to be randomly accessed, then we run into issues regarding the freshness of the data. For instance, if I iterate over a cursor and then want to retrieve the cursor's first element, should a stored copy be returned, or should the cursor re-run the query? If we returned a stored copy, it may not be fresh. And if the the query is re-run, then we're technically dealing with a new cursor.
79
+
80
+ To avoid those issues, we're saying that anyone who needs flexible access to the results of a query should store those results in an array and then access the data as needed.
81
+
82
+ #### Why can't I save an instance of TimeWithZone?
83
+
84
+ MongoDB stores times in UTC as the number of milliseconds since the epoch. This means that the Ruby driver serializes Ruby Time objects only. While it would certainly be possible to serialize a TimeWithZone, this isn't preferable since the driver would still deserialize to a Time object.
85
+
86
+ All that said, if necessary, it'd be easy to write a thin wrapper over the driver that would store an extra time zone attribute and handle the serialization/deserialization of TimeWithZone transparently.
87
+
88
+ #### I keep getting CURSOR_NOT_FOUND exceptions. What's happening?
89
+
90
+ The most likely culprit here is that the cursor is timing out on the server. Whenever you issue a query, a cursor is created on the server. Cursor naturally time out after ten minutes, which means that if you happen to be iterating over a cursor for more than ten minutes, you risk a CURSOR_NOT_FOUND exception.
91
+
92
+ There are two solutions to this problem. You can either:
93
+
94
+ 1. Limit your query. Use some combination of `limit` and `skip` to reduce the total number of query results. This will, obviously, bring down the time it takes to iterate.
95
+
96
+ 2. Turn off the cursor timeout. To do that, invoke `find` with a block, and pass `:timeout => true`:
97
+
98
+ @collection.find({}, :timeout => false) do |cursor|
99
+ cursor.each do |document
100
+ # Process documents here
101
+ end
102
+ end
103
+
104
+ #### I periodically see connection failures between the driver and MongoDB. Why can't the driver retry the operation automatically?
105
+
106
+ A connection failure can indicate any number of failure scenarios. Has the server crashed? Are we experiencing a temporary network partition? Is there a bug in our ssh tunnel?
107
+
108
+ Without further investigation, it's impossible to know exactly what has caused the connection failure. Furthermore, when we do see a connection failure, it's impossible to know how many operations prior to the failure succeeded. Imagine, for instance, that we're using safe mode and we send an `$inc` operation to the server. It's entirely possible that the server has received the `$inc` but failed on the call to `getLastError`. In that case, retrying the operation would result in a double-increment.
109
+
110
+ Because of the indeterminacy involved, the MongoDB drivers will not retry operations on connection failure. How connection failures should be handled is entirely dependent on the application. Therefore, we leave it to the application developers to make the best decision in this case.
111
+
112
+ The drivers will reconnect on the subsequent operation.
@@ -0,0 +1,158 @@
1
+ # GridFS in Ruby
2
+
3
+ GridFS, which stands for "Grid File Store," is a specification for storing large files in MongoDB. It works by dividing a file into manageable chunks and storing each of those chunks as a separate document. GridFS requires two collections to achieve this: one collection stores each file's metadata (e.g., name, size, etc.) and another stores the chunks themselves. If you're interested in more details, check out the [GridFS Specification](http://www.mongodb.org/display/DOCS/GridFS+Specification).
4
+
5
+ ### The Grid class
6
+
7
+ The [Grid class](Mongo/Grid.html) represents the core GridFS implementation. Grid gives you a simple file store, keyed on a unique ID. This means that duplicate filenames aren't a problem. To use the Grid class, first make sure you have a database, and then instantiate a Grid:
8
+
9
+
10
+ @db = Mongo::Connection.new.db('social_site')
11
+ @grid = Grid.new(@db)
12
+
13
+ #### Saving files
14
+ Once you have a Grid object, you can start saving data to it. The data can be either a string or an IO-like object that responds to a #read method:
15
+
16
+
17
+ # Saving string data
18
+ id = @grid.put("here's some string / binary data")
19
+
20
+ # Saving IO data and including the optional filename
21
+ image = File.open("me.jpg")
22
+ id2 = @grid.put(image, :filename => "me.jpg")
23
+
24
+
25
+ Grid#put returns an object id, which you can use to retrieve the file:
26
+
27
+
28
+ # Get the string we saved
29
+ file = @grid.get(id)
30
+
31
+ # Get the file we saved
32
+ image = @grid.get(id2)
33
+
34
+
35
+ #### File metadata
36
+
37
+ There are accessors for the various file attributes:
38
+
39
+
40
+ image.filename
41
+ # => "me.jpg"
42
+
43
+ image.content_type
44
+ # => "image/jpg"
45
+
46
+ image.file_length
47
+ # => 502357
48
+
49
+ image.upload_date
50
+ # => Mon Mar 01 16:18:30 UTC 2010
51
+
52
+ # Read all the image's data at once
53
+ image.read
54
+
55
+ # Read the first 100k bytes of the image
56
+ image.read(100 * 1024)
57
+
58
+
59
+ When putting a file, you can set many of these attributes and write arbitrary metadata:
60
+
61
+
62
+ # Saving IO data
63
+ file = File.open("me.jpg")
64
+ id2 = @grid.put(file,
65
+ :filename => "my-avatar.jpg"
66
+ :content_type => "application/jpg",
67
+ :_id => 'a-unique-id-to-use-in-lieu-of-a-random-one',
68
+ :chunk_size => 100 * 1024,
69
+ :metadata => {'description' => "taken after a game of ultimate"})
70
+
71
+
72
+ #### Safe mode
73
+
74
+ A kind of safe mode is built into the GridFS specification. When you save a file, and MD5 hash is created on the server. If you save the file in safe mode, an MD5 will be created on the client for comparison with the server version. If the two hashes don't match, an exception will be raised.
75
+
76
+
77
+ image = File.open("me.jpg")
78
+ id2 = @grid.put(image, "my-avatar.jpg", :safe => true)
79
+
80
+
81
+ #### Deleting files
82
+
83
+ Deleting a file is as simple as providing the id:
84
+
85
+
86
+ @grid.delete(id2)
87
+
88
+
89
+ ### The GridFileSystem class
90
+
91
+ [GridFileSystem](http://api.mongodb.org/ruby/current/Mongo/GridFileSystem.html) is a light emulation of a file system and therefore has a couple of unique properties. The first is that filenames are assumed to be unique. The second, a consequence of the first, is that files are versioned. To see what this means, let's create a GridFileSystem instance:
92
+
93
+ #### Saving files
94
+
95
+ @db = Mongo::Connection.new.db("social_site")
96
+ @fs = GridFileSystem.new(@db)
97
+
98
+ Now suppose we want to save the file 'me.jpg.' This is easily done using a filesystem-like API:
99
+
100
+
101
+ image = File.open("me.jpg")
102
+ @fs.open("me.jpg", "w") do |f|
103
+ f.write image
104
+ end
105
+
106
+
107
+ We can then retrieve the file by filename:
108
+
109
+
110
+ image = @fs.open("me.jpg", "r") {|f| f.read }
111
+
112
+
113
+ No problems there. But what if we need to replace the file? That too is straightforward:
114
+
115
+
116
+ image = File.open("me-dancing.jpg")
117
+ @fs.open("me.jpg", "w") do |f|
118
+ f.write image
119
+ end
120
+
121
+
122
+ But a couple things need to be kept in mind. First is that the original 'me.jpg' will be available until the new 'me.jpg' saves. From then on, calls to the #open method will always return the most recently saved version of a file. But, and this the second point, old versions of the file won't be deleted. So if you're going to be rewriting files often, you could end up with a lot of old versions piling up. One solution to this is to use the :delete_old options when writing a file:
123
+
124
+
125
+ image = File.open("me-dancing.jpg")
126
+ @fs.open("me.jpg", "w", :delete_old => true) do |f|
127
+ f.write image
128
+ end
129
+
130
+
131
+ This will delete all but the latest version of the file.
132
+
133
+
134
+ #### Deleting files
135
+
136
+ When you delete a file by name, you delete all versions of that file:
137
+
138
+
139
+ @fs.delete("me.jpg")
140
+
141
+
142
+ #### Metadata and safe mode
143
+
144
+ All of the options for storing metadata and saving in safe mode are available for the GridFileSystem class:
145
+
146
+
147
+ image = File.open("me.jpg")
148
+ @fs.open('my-avatar.jpg', w,
149
+ :content_type => "application/jpg",
150
+ :metadata => {'description' => "taken on 3/1/2010 after a game of ultimate"},
151
+ :_id => 'a-unique-id-to-use-instead-of-the-automatically-generated-one',
152
+ :safe => true) { |f| f.write image }
153
+
154
+
155
+ ### Advanced Users
156
+
157
+ Astute code readers will notice that the Grid and GridFileSystem classes are merely thin wrappers around an underlying [GridIO class](http://api.mongodb.org/ruby/current/Mongo/GridIO.html). This means that it's easy to customize the GridFS implementation presented here; just use GridIO for all the low-level work, and build the API you need in an external manager class similar to Grid or GridFileSystem.
158
+
@@ -1,5 +1,17 @@
1
1
  # MongoDB Ruby Driver History
2
2
 
3
+ ### 1.1.3
4
+ 2010-11-29
5
+
6
+ * Distributed reads for replica set secondaries. See /docs/examples/replica_set.rb and
7
+ http://api.mongodb.org/ruby/current/file.REPLICA_SETS.html for details.
8
+ * Note: when connecting to a replica set, you must use Connection#multi.
9
+ * Cursor#count takes optional skip and limit
10
+ * Collection#ensure_index for caching index creation calls
11
+ * Collection#update and Collection#remove now return error object when using safe mode
12
+ * Important fix for int/long serialization on bug introduced in 1.0.9
13
+ * Numerous tweaks and bug fixes.
14
+
3
15
  ### 1.1.2
4
16
  2010-11-4
5
17
 
@@ -0,0 +1,77 @@
1
+ # Replica Sets in Ruby
2
+
3
+ Here follow a few considerations for those using the MongoDB Ruby driver with [replica sets](http://www.mongodb.org/display/DOCS/Replica+Sets).
4
+
5
+ ### Setup
6
+
7
+ First, make sure that you've configured and initialized a replica set.
8
+
9
+ Use `Connection.multi` to connect to a replica set:
10
+
11
+ @connection = Connection.multi([['n1.mydb.net', 27017], ['n2.mydb.net', 27017], ['n3.mydb.net', 27017]])
12
+
13
+ The driver will attempt to connect to a master node and, when found, will replace all seed nodes with known members of the replica set.
14
+
15
+ ### Read slaves
16
+
17
+ If you want to read from a seconday node, you can pass :read_secondary => true to Connection#multi.
18
+
19
+ @connection = Connection.multi([['n1.mydb.net', 27017], ['n2.mydb.net', 27017], ['n3.mydb.net', 27017]],
20
+ :read_secondary => true)
21
+
22
+ A random secondary will be chosen to be read from. In a typical multi-process Ruby application, you'll have a good distribution of reads across secondary nodes.
23
+
24
+ ### Connection Failures
25
+
26
+ Imagine that either the master node or one of the read nodes goes offline. How will the driver respond?
27
+
28
+ If any read operation fails, the driver will raise a *ConnectionFailure* exception. It then becomes the client's responsibility to decide how to handle this.
29
+
30
+ If the client decides to retry, it's not guaranteed that another member of the replica set will have been promoted to master right away, so it's still possible that the driver will raise another *ConnectionFailure*. However, once a member has been promoted to master, typically within a few seconds, subsequent operations will succeed.
31
+
32
+ The driver will essentially cycle through all known seed addresses until a node identifies itself as master.
33
+
34
+ ### Recovery
35
+
36
+ Driver users may wish to wrap their database calls with failure recovery code. Here's one possibility, which will attempt to connection
37
+ every half second and time out after thirty seconds.
38
+
39
+ # Ensure retry upon failure
40
+ def rescue_connection_failure(max_retries=60)
41
+ success = false
42
+ retries = 0
43
+ while !success
44
+ begin
45
+ yield
46
+ success = true
47
+ rescue Mongo::ConnectionFailure => ex
48
+ retries += 1
49
+ raise ex if retries >= max_retries
50
+ sleep(0.5)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ # Wrapping a call to #count()
57
+ rescue_connection_failure do
58
+ @db.collection('users').count()
59
+ end
60
+
61
+ Of course, the proper way to handle connection failures will always depend on the individual application. We encourage object-mapper and application developers to publish any promising results.
62
+
63
+ ### Testing
64
+
65
+ The Ruby driver (>= 1.0.6) includes some unit tests for verifying replica set behavior. They reside in *tests/replica_sets*. You can run them individually with the following rake tasks:
66
+
67
+ rake test:replica_set_count
68
+ rake test:replica_set_insert
69
+ rake test:pooled_replica_set_insert
70
+ rake test:replica_set_query
71
+
72
+ Make sure you have a replica set running on localhost before trying to run these tests.
73
+
74
+ ### Further Reading
75
+
76
+ * [Replica Sets](http://www.mongodb.org/display/DOCS/Replica+Set+Configuration)
77
+ * [Replics Set Configuration](http://www.mongodb.org/display/DOCS/Replica+Set+Configuration)
@@ -2,7 +2,7 @@
2
2
 
3
3
  This tutorial gives many common examples of using MongoDB with the Ruby driver. If you're looking for information on data modeling, see [MongoDB Data Modeling and Rails](http://www.mongodb.org/display/DOCS/MongoDB+Data+Modeling+and+Rails). Links to the various object mappers are listed on our [object mappers page](http://www.mongodb.org/display/DOCS/Object+Mappers+for+Ruby+and+MongoDB).
4
4
 
5
- Interested in GridFS? See [GridFS in Ruby](http://www.mongodb.org/display/DOCS/GridFS+in+Ruby).
5
+ Interested in GridFS? See [GridFS in Ruby](file.GridFS.html).
6
6
 
7
7
  As always, the [latest source for the Ruby driver](http://github.com/mongodb/mongo-ruby-driver) can be found on [github](http://github.com/mongodb/mongo-ruby-driver/).
8
8
 
@@ -0,0 +1,28 @@
1
+ # Write Concern in Ruby
2
+
3
+ ## Setting the write concern
4
+
5
+ Write concern is set using the `:safe` option. There are several possible options:
6
+
7
+ @collection.save({:doc => 'foo'}, :safe => true)
8
+ @collection.save({:doc => 'foo'}, :safe => {:w => 2})
9
+ @collection.save({:doc => 'foo'}, :safe => {:w => 2, :wtimeout => 200})
10
+ @collection.save({:doc => 'foo'}, :safe => {:w => 2, :wtimeout => 200, :fsync => true})
11
+
12
+ The first, `true`, simply indicates that we should request a response from the server to ensure that to errors have occurred. The second, `{:w => 2}`forces the server to wait until at least two servers have recorded the write. The third does the same but will time out if the replication can't be completed in 200 milliseconds. The fourth forces an fsync on each server being written to (note: this option is rarely necessary and will have a dramaticly negative effect on performance).
13
+
14
+ ## Write concern inheritance
15
+
16
+ The Ruby driver allows you to set write concern on each of four levels: the connection, database, collection, and write operation.
17
+ Objects will inherit the default write concern from their parents. Thus, if you set a write concern of `{:w => 1}` when creating
18
+ a new connection, then all databases and collections created from that connection will inherit the same setting. See this code example:
19
+
20
+ @con = Mongo::Connection.new('localhost', 27017, :safe => {:w => 2})
21
+ @db = @con['test']
22
+ @collection = @db['foo']
23
+ @collection.save({:name => 'foo'})
24
+
25
+ @collection.save({:name => 'bar'}, :safe => false)
26
+
27
+ Here, the first call to Collection#save will use the inherited write concern, `{:w => 2}`. But notice that the second call
28
+ to Collection#save overrides this setting.
@@ -3,7 +3,7 @@
3
3
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
4
 
5
5
  module Mongo
6
- VERSION = "1.1.2"
6
+ VERSION = "1.1.3"
7
7
  end
8
8
 
9
9
  module Mongo
@@ -40,6 +40,7 @@ require 'bson'
40
40
  require 'mongo/util/conversions'
41
41
  require 'mongo/util/support'
42
42
  require 'mongo/util/core_ext'
43
+ require 'mongo/util/pool'
43
44
  require 'mongo/util/server_version'
44
45
 
45
46
  require 'mongo/collection'