The Collection API is designed to be very extensible, allowing the use of third-party libraries for building documents (e.g. use something else than the embedded BSON library), including specific serializers and deserializers. For example, that’s the case of the ReactiveMongo Play plugin, which relies on the Play JSON library instead.
This is very useful when you don’t want to explicitly convert your objects into yet another different structure – if your application uses JSON, it is perfectly understandable to want to avoid using BSON only for dealing with MongoDB.
The Collection trait
This trait is almost empty.
All collections implementations must mix this trait in. They also provide implicit objects of type CollectionProducer that make new (specialized) instances of them. Since db.collection() is parametrized with C <: Collection and accepts an implicit CollectionProducer[C], the returned instance of collection can be inferred to the right type if there is only one producer in the implicit scope, which is a typical situation.
Most implementations actually extend another trait, GenericCollection.
The GenericCollection trait
This trait is much more complete than Collection. It defines common methods, like find(), update(), remove() and insert(), among others. One particularity of them is that they may be given …
GenericCollection takes 3 type parameters:
Structure is a type which instances may eventually be deserialized or serialized into BSON. It may be BSONDocument of course (as it is in the default Collection implementation), but can be a JSON objector any other third-party structure.
Reader[T] is a type constructor that represents something that knows how to produce a new instance of T from a Structure instance (T being the type parameter of Reader). In the default Collection implementation, this is BSONDocumentReader[_].
Writer[T] is a type constructor that represents something that knows how to produce a new instance of Structure from a T instance (T being the type parameter of Reader). In the default Collection implementation, this is BSONDocumentWriter[_].
GenericCollection extends another trait, GenericHandlers, which takes the same type arguments and is used to do the conversions:
Here, BufferReader and BufferWriter denote types that define how to read or write Structure from/to a byte string, while StructureReader and StructureWriter define how to convert a T instance into Structure and vice versa. In other words, StructureReader turns a given abstract reader, useless to ReactiveMongo, into a GenericReader that ReactiveMongo can handle.
Let’s take an example of how these types are used with find(), which is defined like this:
This method takes a selector (or query), of type S. This object is then transformed into BSON thanks to the implicit swriter parameter. Moreover, you can notice that the return type is another trait, GenericQueryBuilder, with the same parameter types.
The GenericQueryBuilder trait
A GenericQueryBuilder, like its name says it, helps building and customizing the query. As GenericCollection, it extends GenericHandlers.
The default implementation in ReactiveMongo, BSONCollection. It relies on the embedded BSON library, with BSONCollection as the Structure, and BSONDocumentReader and BSONDocumentWriter as the de/serializer typeclasses.
The implementation in the Play plugin, JSONCollection. It uses JsObject (a JSON object) as the Structure, and the de/serializer typeclasses Writes and Reads.