Skip to content

Commit ff0069e

Browse files
authored
Merge pull request #905 from estolfo/RUBY-1271-tutorial
RUBY-1271 Tutorial documentation for 3.6
2 parents 879e56e + 0a579e3 commit ff0069e

File tree

4 files changed

+214
-0
lines changed

4 files changed

+214
-0
lines changed

docs/ruby-driver-tutorials.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ operations available in the Ruby driver.
1919
/tutorials/ruby-driver-crud-operations
2020
/tutorials/ruby-driver-collection-tasks
2121
/tutorials/ruby-driver-projections
22+
/tutorials/ruby-driver-sessions
23+
/tutorials/ruby-driver-change-streams
2224
/tutorials/ruby-driver-admin-tasks
2325
/tutorials/ruby-driver-indexing
2426
/tutorials/ruby-driver-collations
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
==============
2+
Change Streams
3+
==============
4+
5+
.. default-domain:: mongodb
6+
7+
.. contents:: On this page
8+
:local:
9+
:backlinks: none
10+
:depth: 1
11+
:class: singlecol
12+
13+
As of version 3.6 of the MongoDB server, a new ``$changeStream`` pipeline stage is supported in the aggregation
14+
framework. The Ruby driver provides an API for receiving notifications for changes to a particular collection using this
15+
new pipeline stage. Although you can create a change stream using the pipeline operator and aggregation framework
16+
directly, it is recommended to use the driver API described below as the driver resumes the change stream if there is
17+
timeout or network error.
18+
19+
Change streams on the server requires a ``"majority"`` read concern or no read concern.
20+
21+
Change streams do not work properly with JRuby because of the issue documented here_.
22+
23+
.. _here: https://github.com/jruby/jruby/issues/4212
24+
25+
Namely, JRuby eagerly evaluates ```#next`` on an Enumerator in a background green thread.
26+
So calling ```#next`` on the change stream will cause getmores to be called in a loop in the background.
27+
28+
Watching for changes on a particular collection
29+
-----------------------------------------------
30+
31+
A change stream is created by calling the ``#watch`` method on a collection:
32+
33+
.. code-block:: ruby
34+
35+
stream = collection.watch
36+
collection.insert_one(a: 1)
37+
doc = stream.to_enum.next
38+
process(doc)
39+
40+
41+
You can also receive the notifications as they are available:
42+
43+
.. code-block:: ruby
44+
45+
stream = client[:test].watch
46+
enum = stream.to_enum
47+
while doc = enum.next
48+
process(doc)
49+
end
50+
51+
52+
The change stream can take filters in the aggregation framework pipeline operator format:
53+
54+
.. code-block:: ruby
55+
56+
stream = collection.watch([{'$match' => { 'operationType' => {'$in' => ['insert', 'replace'] } } },
57+
{'$match' => { 'fullDocument.n' => { '$gte' => 1 } } }
58+
])
59+
enum = stream.to_enum
60+
while doc = enum.next
61+
process(doc)
62+
end
63+
64+
Close a Change Stream
65+
---------------------
66+
67+
You can close a Change Stream by calling the ``#close`` method:
68+
69+
.. code-block:: ruby
70+
71+
stream = collection.watch
72+
collection.insert_one(a: 1)
73+
doc = stream.to_enum.next
74+
process(doc)
75+
stream.close

docs/tutorials/ruby-driver-create-client.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,12 @@ Ruby Options
407407
- ``Integer``
408408
- none
409409

410+
* - ``:retry_writes``
411+
- If a single-statement write operation fails from a network error, the driver automatically retries it once
412+
when connected to server versions 3.6+.
413+
- ``Boolean``
414+
- false
415+
410416

411417
Details on Timeout Options
412418
--------------------------
@@ -530,3 +536,20 @@ When ``#close`` is called on a client by any thread, all connections are closed:
530536
.. code-block:: ruby
531537

532538
client.close
539+
540+
Details on Retryable Writes
541+
---------------------------
542+
543+
If the ``retry_writes`` option is set to true, the driver will retry single-statement write operations that fail from
544+
a network error. The driver automatically retries the operation once.
545+
546+
Most of the write methods you use day-to-day on a collection will be retryable in 3.6. They are:
547+
548+
- ``collection#insert_one``
549+
- ``collection#update_one``
550+
- ``collection#delete_one``
551+
- ``collection#replace_one``
552+
- ``collection#find_one_and_update``
553+
- ``collection#find_one_and_replace``
554+
- ``collection#find_one_and_delete``
555+
- ``collection#bulk_write`` # for all single statement ops (i.e. not for ``update_many`` or ``delete_many``)
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
============================
2+
Creating and using Sessions
3+
============================
4+
5+
.. default-domain:: mongodb
6+
7+
.. contents:: On this page
8+
:local:
9+
:backlinks: none
10+
:depth: 1
11+
:class: singlecol
12+
13+
14+
Version 3.6 of the server introduces the concept of logical sessions for clients.
15+
A session is an abstract concept that represents a set of sequential operations executed
16+
by an application that are related in some way. A session object can be create via a ``Mongo::Client``
17+
and passed to operation methods that should be executed in the context of that session.
18+
19+
Please note that sessions are not thread safe. They can only be used by one thread at a time.
20+
21+
Creating a session from a ``Mongo::Client``
22+
-------------------------------------------
23+
24+
A session can be created by calling the ``start_session`` method on a client:
25+
26+
.. code-block:: ruby
27+
28+
session = client.start_session
29+
30+
31+
It is valid to call ``start_session`` with no options set. This will result in a
32+
session that has no effect on the operations performed in the context of that session,
33+
other than to include a session ID in commands sent to the server. Please see the API docs for all supported
34+
session options.
35+
36+
An error will be thrown if the driver is connected to a deployment that does not support sessions and the
37+
``start_session`` method is called.
38+
39+
Note that server sessions are discarded server-side if not used for a certain period of time. That said,
40+
be aware that if the application calls ``#start_session`` on a client and waits more than 1 minute to use
41+
the session, it risks getting errors due to the session going stale before it is used.
42+
43+
44+
Using a session
45+
---------------
46+
A session object can be passed to most driver methods so that the operation can be executed in the
47+
context of that session. Please see the API docs for which methods support a session argument.
48+
49+
Create a session and execute an insert, then a find using that session:
50+
51+
.. code-block:: ruby
52+
53+
session = client.start_session
54+
client[:artists].insert_one({ :name => 'FKA Twigs' }, session: session)
55+
client[:artists].find({ :name => 'FKA Twigs' }, limit: 1, session: session).first
56+
57+
If you like to call methods on a ``Mongo::Collection::View`` in the context of a particular session, you can create the
58+
``Mongo::Collection::View`` with the session and then call methods on it:
59+
60+
.. code-block:: ruby
61+
62+
session = client.start_session(causal_consistency: true)
63+
view = client[:artists].find({ :name => 'FKA Twigs' }, session: session)
64+
view.count # will use the session
65+
66+
You can also pass the session option to the methods directly. This session will override any session associated with
67+
the ``Mongo::Collection::View``:
68+
69+
.. code-block:: ruby
70+
71+
session = client.start_session
72+
second_session = client.start_session
73+
view = client[:artists].find({ :name => 'FKA Twigs' }, session: session)
74+
view.count(session: second_session) # will use the second_session
75+
76+
Causal Consistency
77+
------------------
78+
A causally consistent session will let you read your writes and guarantee monotonically increasing
79+
reads from secondaries.
80+
To create a causally consistent session, set the ``causal_consistency`` option to true:
81+
82+
.. code-block:: ruby
83+
84+
session = client.start_session(causal_consistency: true)
85+
86+
# The update message goes to the primary.
87+
collection = client[:artists]
88+
collection.update_one({ '_id' => 1 }, { '$set' => { 'x' => 0 } }, session: session)
89+
90+
# Read your write, even when reading from a secondary!
91+
collection.find({ '_id' => 1 }, session: session).first
92+
93+
# This query returns data at least as new as the previous query,
94+
# even if it chooses a different secondary.
95+
collection.find({ '_id' => 2 }, session: session).first
96+
97+
Since unacknowledged writes don't receive a response from the server (or don't wait for a response), the driver
98+
has no way of keeping track of where the unacknowledged write is in logical time. Therefore, causally
99+
consistent reads are not causally consistent with unacknowledged writes.
100+
101+
Note that if you set the causal_consistency option to nil as in ``(causal_consistency: nil)``, it will be interpreted
102+
as false.
103+
104+
End a session
105+
-------------
106+
To end a session, call the ``end_session`` method:
107+
108+
.. code-block:: ruby
109+
110+
session.end_session
111+
112+
The Ruby driver will then add the id for the corresponding server session to a pool for reuse.
113+
When a client is closed, the driver will send a command to the server to end all sessions it has cached
114+
in its server session pool. You may see this command in your logs when a client is closed.

0 commit comments

Comments
 (0)