[GODRIVER-2141] Add a recursive option to Map() Created: 27/Aug/21 Updated: 27/Oct/23 Resolved: 20/Sep/21 |
|
| Status: | Closed |
| Project: | Go Driver |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | New Feature | Priority: | Minor - P4 |
| Reporter: | Nathan Leniz | Assignee: | Benji Rewis (Inactive) |
| Resolution: | Gone away | Votes: | 0 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Issue Links: |
|
||||||||
| Description |
|
Requesting a similar function to Map() or an option that enables Map() to recursively convert bson.D to a map. Due to ordering, bson.D is preferable to bson.M and we're using bson.D exclusively in the developing Go documentation. This type isn't ideal when demonstrating output to users since everything is prepended with "Key" and "Value". The Map() function provides a workaround for simple documents but breaks down on documents with arrays of documents, as it doesn't convert them. Example:
|
| Comments |
| Comment by PM Bot [ 20/Sep/21 ] | |||
|
There hasn't been any recent activity on this ticket, so we're resolving it. Thanks for reaching out! Please feel free to comment on this if you're able to provide more information. | |||
| Comment by Benji Rewis (Inactive) [ 03/Sep/21 ] | |||
|
Would it be possible to use bson.MarshalExtJSON instead of json.MarshalIndent? The indents may not be there, but I believe those “Key” and “Value” printouts should be gone. This is actually a very interesting little problem haha. All the solutions I’ve proposed above are slightly problematic. #3 might be API-breaking upon closer inspection. There is in fact existing behavior for calling json.Marshal on a bson.D. See code snippet below:
Implementing a custom primitive.D#MarshalJSON() may break users’ code that relies on the existing marshaling behavior. However, #1 and #2 are more complex than they appear. The main issue is that it’s quite difficult to write a function that converts all embedded primitive.Ds to primitive.Ms for any generic container of a primitive.D (note that we could only recurse through bson.As, but that’s not really an exhaustive solution here). See the most recent comment on a draft implementation of primitive.D#RecursiveMap() that I put up. #1 and #2 require some complex reflection logic to account for a generic, embedded slice containing bson.Ds. And, unfortunately, complex reflection logic can introduce bugs (even we find Go reflection to be quite opaque), so we’d like to save that as a last resort. Let me know if MarshalExtJSON would work. We could even implement MarshalExtJSONIndent if that’s something that you’d find useful. If that doesn’t work for some reason, it might be time to reflect (pun intended). Another alternative may be to implement the fmt.Stringer interface for primitive.D, but that’s a little more involved. | |||
| Comment by Nathan Leniz [ 31/Aug/21 ] | |||
|
Nice summary. I agree that modifying primitive.D#Map to this behavior is the least desirable route, and adding an option to it isn't ideal either. #3 seems like the best choice. Will we default to canonical extended JSON? | |||
| Comment by Benji Rewis (Inactive) [ 31/Aug/21 ] | |||
|
Thanks again for the request nathan.leniz! bson.D is just a type alias of primitive.D. So, the Map function that’s being calling in your example is primitive.D#Map(). As you mentioned, primitive.D#Map() is shallowly iterative: it will only make a new primitive.M (aliased by bson.M) with top-level keys and values copied from the original primitive.D. This shallow iteration means that any embedded arrays of documents (as in your example) or embedded documents will retain their original type. So, when you call json.MarshalIndent(…), those pesky “Key” and “Value” prepensions will remain on embedded bson.Ds or bson.As of bson.Ds. Modifying primitive.D#Map() to be recursive is arguably an API-breaking change, as users may be relying on those “Key” and “Value” prepensions (even if they’re “buggy”). So, we have a couple options:
Any preference? I'm leaning toward #3. | |||
| Comment by Benji Rewis (Inactive) [ 30/Aug/21 ] | |||
|
Thanks for the feature request nathan.leniz! Taking a look now. |