OK, thanks, now I can rule out several possibilities I was thinking of, and not worry about ones I hadn’t even imagined either.
The mongos node will be using the DBClient* classes in the C++ code of the core server. Think of it as being more or less that it is using the C++ driver to connect to the shards and configsvr replica set.
I soon found DBClientReplicaSet::selectNodeUsingTags() (mongo/dbclient_rs.cpp at 6fe78a092be6b3a87ec9a91693c7dc77bd45fe5e · mongodb/mongo · GitHub). The logic is delegated out the to ReplicaSetMonitor class’s getHostOrRefresh() function and this ultimately comes to SetState::getMatchingHosts(). In the case of readPreference: “nearest” with tags the most important code block appears to be this: mongo/replica_set_monitor.cpp at v4.2 · mongodb/mongo · GitHub
I was hoping to find the answer here but the code disagrees. If { “something”: “x”, “region”: “a” } matches exactly one node as your starting scenario showed I expect that to be returned, no falling back to { “something”: “x” }.
Please take a look at the code and tell me what you think!
FYI criteria.tags.getTagBSON() will return an array, not a single BSON object like I was wondering about earlier. So BSONForEach(tagElem, criteria.tags.getTagBSON()) { … many lines … } would iterate first round with { “something”: “x”, “region”: “a” } as the “tag” value and then, if it finds nothing, do a second round with { "something": "x" }
as “tag”. I am confident this order of tags will be kept as the user specified it.
If there are any matches in a pass of the loop the function will return, either at line 1150 or 1202. I.e. find anything with { “something”: “x”, “region”: “a” } and the loop iteration with { “something”: “x” } will never happen.
If the readPreference is “primary”, “secondary” or “primaryPreferred” SetState::getMatchingHosts() can be used recursively and that would be another thing to think about, but in the case of “nearest” the host selected in this L1133-L2103 block is the selected node.
I assume the minOpTime value will be set only when maxStalenessSeconds is used, which you haven’t, and besides the nodes would have to be at least 90 secs behind which is high.
The latency threshold will matter (15ms + best latency of any node) but I believe you would have read about that already and be aware of that.