Probably since change streams were implemented in 1.9.0 (
CDRIVER-2233), they prefer the collection readConcern over the readConcern passed in "opts".
Details: _mongoc_change_stream_new_from_collection sets stream->read_concern to the collection's read concern, and copies the user-supplied options to stream->opts. Then in _make_cursor, we copy stream->opts to a local variable "command_opts", resulting in something like:
We then append stream->read_concern to command_opts:
Now command_opts has two readConcern fields. A few layers deeper we call _mongoc_read_write_opts_parse, which is generated from IDL (
CDRIVER-2373). For speed and simplicity, I deliberately implemented last-field-wins for duplicate fields in the IDL parsers instead of adding any logic to detect duplicates. In this case the readConcern from the collection is last, and that is the readConcern used.