Need some help to figure out why nested bson.M doesn’t work occasionally.
For the following Golang structs stored in a MongoDb collection for type A:
type A struct {
Id primitive.ObjectID
Random1 string
Parents []B
Random2 int
}
type B struct {
Id primitive.ObjectID
Random3 string
Children []C
Random4 int
}
type C struct {
Random5 string
Name Name
Random6 int
}
type Name struct {
FirstName string
LastName string
}
The following filter for FindOne(), which uses two bson.M, worked in most situations but failed to find a match in about 10% runs
In Go, maps are intentionally non-deterministic. This is mentioned in the article Go maps in action specifically in the section Iteration Order where it is stated:
When iterating over a map with a range loop, the iteration order is not specified and is not guaranteed to be the same from one iteration to the next.
So, while querying in MongoDB, in most cases the order of keys does not matter, so we take advantage of the concise syntax of Go maps.
In filter1 you are matching on a BSON document where field order matters. Instead, you should use the approach from filter3 which worked well for you. Also, it is a shorter and clearer filter declaration:
Whereas when you use bson.D instead of bson.M, you will see deterministic behavior as you noted in filter2.
The only two cases where the order is significant are for generic commands(where the first key has to be the command name) and index specifications(where the order determines the structure of the index), and in those cases, it’s recommended to use bson.D instead of bson.M.
Here if you note, the query is using nested bson.M. Specifically, in the "parents.0.chilren.0.name" field, the matching order is crucial and needs to be definite whereas in the filter3 it doesn’t matter which comes first because it directly points out to the specific keys which are "parents.0.chilren.0.name.first_name" and "parents.0.chilren.0.name.last_name"
To explain it further, consider the following example: