[GODRIVER-2660] Update "FindOne" to accept a result output argument, remove SingleResult Created: 20/Nov/22  Updated: 11/Mar/23

Status: Backlog
Project: Go Driver
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Unknown
Reporter: Matt Dale Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
related to GODRIVER-1790 Remove use of SingleResult in favor o... Closed
Backwards Compatibility: Major Change

 Description   

The current FindOne API returns a SingleResult instead of a result/cursor and an error. That confuses users for a number of reasons:

  1. All other operation functions return either a result type and an error or a Cursor and an error. FindOne breaks that pattern and returns a result+error
    "handle" (i.e. the SingleResult) that you then have to make additional calls to, leading to confusion.
  2. SingleResult has an Err() function and Decode also returns an error. That's similar to the Cursor API where users need to check Err() after every call to Next(), but users don't actually need to check the Err() error after calling Decode on a SingleResult, which is confusing.

Instead, we should change the FindOne API to accept an output parameter and return a single error. To support the DecodeBytes use case, we would add a special behavior if the input type is a *bson.Raw that returns the result BSON document bytes instead of unmarshaling it.

E.g. FindOne function signature:

func (c *Collection) FindOne(ctx context.Context, val interface{}, opts ...*options.FindOneOptions) error

E.g. usage:

coll := client.Database("test").Collection("test")
 
var myValue struct {
    S string
    I int
}
err := coll.FindOne(context.Background(), &myValue)
if err != nil {
    panic(err)
}

E.g. special *bson.Raw usage:

coll := client.Database("test").Collection("test")
 
var myBytes bson.Raw
err := coll.FindOne(context.Background(), &myBytes)
if err != nil {
    panic(err)
}



 Comments   
Comment by Matt Dale [ 11/Mar/23 ]

We've decided to not include this in the Go Driver 2.0 scope for the following reasons:

  • The existing design of Find and FindOne follow the same conventions as the Go database/sql methods QueryContext and QueryRowContext, respectively. The returned types Cursor and SingleResult are also conventionally similar to the Go database/sql types Row and Rows, respectively. As a result, users who have used the database/sql package may already be familiar with the similar conventions in the Go driver APIs.
    • One noteworthy distinction is that the Go Rows.Next cursor iteration method uses the context passed to QueryContext when calling for more results from the DB. In contrast, the Go driver Cursor.Next cursor iteration method requires the user specify a context for each call.
  • Some of the confusion over how to use a SingleResult seems to stem from insufficient documentation on the SingleResult.Err method, which was recently improved here).

As a result, it's not clear that the proposed API change is a net improvement over the existing API and doesn't seem worth the migration pain of caused by changing the syntax of FindOne.

Generated at Thu Feb 08 08:39:06 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.