DATAMONGO-2001 - Count within transaction should return only the total count of documents visible to the specific session.
We now delegate count operations within an active transaction to an aggregation.
Once `MongoTemplate` detects an active transaction, all exposed `count()` methods are converted and delegated to the
aggregation framework using `$match` and `$count` operators, preserving `Query` settings, such as `collation`.
The following snippet of `count` inside the session bound closure
session.startTransaction();
template.withSession(session)
.execute(action -> {
action.count(query(where("state").is("active")), Step.class)
...
runs:
db.collection.aggregate(
[
{ $match: { state: "active" } },
{ $count: "totalEntityCount" }
]
)
instead of:
db.collection.find( { state: "active" } ).count()
Original pull request: #568.
pull/570/merge
Christoph Strobl8 years agocommitted byMark Paluch
@ -2116,7 +2119,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@@ -2116,7 +2119,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
Assert.notNull(aggregation,"Aggregation pipeline must not be null!");
Assert.notNull(outputType,"Output type must not be null!");
@ -2847,7 +2851,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@@ -2847,7 +2851,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@ -3498,6 +3501,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@@ -3498,6 +3501,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@ -3508,6 +3512,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@@ -3508,6 +3512,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@ -3531,5 +3536,55 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
@@ -3531,5 +3536,55 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
// native MongoDB objects that offer methods with ClientSession must not be proxied.
@ -2639,7 +2642,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@@ -2639,7 +2642,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@ -3231,6 +3234,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@@ -3231,6 +3234,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@ -3241,6 +3245,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@@ -3241,6 +3245,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@ -3264,6 +3269,57 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
@@ -3264,6 +3269,57 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
// native MongoDB objects that offer methods with ClientSession must not be proxied.
<1> Enable transaction synchronization during Template API configuration.
@ -186,26 +185,26 @@ The `MongoTransactionManager` binds a `ClientSession` to the thread. `MongoTempl
@@ -186,26 +185,26 @@ The `MongoTransactionManager` binds a `ClientSession` to the thread. `MongoTempl
@Configuration
static class Config extends AbstractMongoConfiguration {
@ -230,18 +229,18 @@ Using the plain MongoDB reactive driver API a `delete` within a transactional fl
@@ -230,18 +229,18 @@ Using the plain MongoDB reactive driver API a `delete` within a transactional fl
<1> First we obviously need to initiate the session.
@ -263,9 +262,9 @@ accordingly. This allows you to express the above flow simply as the following:
@@ -263,9 +262,9 @@ accordingly. This allows you to express the above flow simply as the following:
====
[source,java]
----
Mono<DeleteResult> result = template.inTransaction() <1>
Mono<DeleteResult> result = template.inTransaction() <1>
<2> Operate within the `ClientSession`. Each `execute(…)` unit of work callback initiates a new transaction in the scope of the same `ClientSession`.
@ -280,20 +279,77 @@ reactive flow of `execute(…)` that are not propagated to outside of the callba
@@ -280,20 +279,77 @@ reactive flow of `execute(…)` that are not propagated to outside of the callba
<2> Operate within the `ClientSession`. The transaction is committed after this is done or rolled back if an
error occurs here.
<3> An error outside the transaction flow has no affect on the previous transactional execution.
====
== Special behavior inside transactions
Inside transactions MongoDB server has a slightly different behavior.
*Connection Settings*
The MongoDB drivers offer a dedicated replica set name configuration option turing the driver into an auto detection
mode. This option helps identifying replica set master nodes and command routing during a transaction.
INFO: Make sure to add `replicaSet` to the MongoDB Uri. Please refer to https://docs.mongodb.com/manual/reference/connection-string/#connections-connection-options[connection string options] for further details.
*Collection Operations*
MongoDB does *not* support collection operations, such as collection creation, within a transaction. This also
affects the on the fly collection creation that happens on first usage. Therefore make sure to have all required
structures in place.
*Count*
MongoDB `count` operates upon collection statistics which may not reflect the actual situation within a transaction.
The server responds with _error 50851_ when issuing a `count` command inside of a multi-document transaction.
Once `MongoTemplate` detects an active transaction, all exposed `count()` methods are converted and delegated to the
aggregation framework using `$match` and `$count` operators, preserving `Query` settings, such as `collation`.
====
The following snippet of `count` inside the session bound closure