Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request: BSON stabilize ordering of map keys (instead of GoLang's random ordering) #381

Open
bgehman opened this issue Nov 6, 2019 · 1 comment

Comments

@bgehman
Copy link

bgehman commented Nov 6, 2019

I'd like to leverage the Upsert() capabilities of Mongo, and know when a document has changed on the Upsert when using GoLang maps. Specifically I want ChangeInfo.Updated to be 0 when the document has not changed.

Background
When it comes to JSON & BSON maps, there are differences in their respective specs:

  • JSON cares not about the ordering of keys in maps (keys are a "set" and ordering is not implied)
  • BSON strictly enforces ordering in maps (keys are still a "set" but ordering is implied)

Coupled with the fact that GoLang intentionally randomizes the order when walking over a map (ie: range <map>) means that 99% of my Upserts are coming back indicating that the document changed (when it really didn't). The only thing that changed was the randomized ordering of the keys by the lower level GoLang range function when walking maps.

This is the LOC that is the culprit (range'ing over the map):

for _, k := range v.MapKeys() {

If the addMap() function would fetch the map's keys, sort them, and then addElem() in that sorted order I'd be "set". The current code is taking GoLang's map random ordering (more akin to JSON), and encoding it as a strict ordering in BSON.

I've also tried using bson.D with no luck. Whenever Upsert()'ing with bson.D the order is preserved (not random in Mongo) -- however ChangeInfo.Updated is never 0 on identical / repeated calls.

What works:

  • golang struct's

What doesn't work:

  • bson.M (ie: map[string]interface{})
  • bson.D (ie: []DocElem)

I'm not able to model the docs via GoLang struct as this middleware component is agnostic to the model of the docs (more akin to a generic JSON processor), but it does need to know if/when the document has been modified on the Upsert().


What version of MongoDB are you using (mongod --version)?

Doesn't matter

What version of Go are you using (go version)?

Doesn't matter (greater than 1.0)

What operating system and processor architecture are you using (go env)?

Doesn't matter

What did you do?

Upsert a bson.M document (ie: map[string]interface{})
Repeated calls of the same map result in ChangeInfo.Updated not equal to 0, depending on the randomized order of golangs range <map> and BSON's internal strict ordering.

Can you reproduce the issue on the latest development branch?

Haven't tried, but a code review show the same range <map> problem (ie: randomized ordering of map keys).

@bgehman
Copy link
Author

bgehman commented Nov 6, 2019

Actually, struct is broken too. In all cases, an Upsert (via any method) results in ChangeInfo.Updated not equal to 0 even though the document is not changed.

Since this driver is abandon-ware, we are moving to mongo-go-driver. That other driver does still have the range <map> problem, but at least there are ways to detect if documents have changed on upsert with it. L8r.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant