Skip to content

Commit 60f76f5

Browse files
authored
GODRIVER-1807 Add UpdateByID (#553)
1 parent 84d9e4a commit 60f76f5

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

mongo/collection.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,27 @@ func (coll *Collection) updateOrReplace(ctx context.Context, filter bsoncore.Doc
581581
return res, err
582582
}
583583

584+
// UpdateByID executes an update command to update the document whose _id value matches the provided ID in the collection.
585+
// This is equivalent to running UpdateOne(ctx, bson.D{{"_id", id}}, update, opts...).
586+
//
587+
// The id parameter is the _id of the document to be updated. It cannot be nil. If the ID does not match any documents,
588+
// the operation will succeed and an UpdateResult with a MatchedCount of 0 will be returned.
589+
//
590+
// The update parameter must be a document containing update operators
591+
// (https://docs.mongodb.com/manual/reference/operator/update/) and can be used to specify the modifications to be
592+
// made to the selected document. It cannot be nil or empty.
593+
//
594+
// The opts parameter can be used to specify options for the operation (see the options.UpdateOptions documentation).
595+
//
596+
// For more information about the command, see https://docs.mongodb.com/manual/reference/command/update/.
597+
func (coll *Collection) UpdateByID(ctx context.Context, id interface{}, update interface{},
598+
opts ...*options.UpdateOptions) (*UpdateResult, error) {
599+
if id == nil {
600+
return nil, ErrNilValue
601+
}
602+
return coll.UpdateOne(ctx, bson.D{{"_id", id}}, update, opts...)
603+
}
604+
584605
// UpdateOne executes an update command to update at most one document in the collection.
585606
//
586607
// The filter parameter must be a document containing query operators and can be used to select the document to be

mongo/integration/collection_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,93 @@ func TestCollection(t *testing.T) {
484484
}
485485
})
486486
})
487+
mt.RunOpts("update by id", noClientOpts, func(mt *mtest.T) {
488+
mt.Run("empty update", func(mt *mtest.T) {
489+
_, err := mt.Coll.UpdateByID(mtest.Background, "foo", bson.D{})
490+
assert.NotNil(mt, err, "expected error, got nil")
491+
})
492+
mt.Run("nil id", func(mt *mtest.T) {
493+
_, err := mt.Coll.UpdateByID(mtest.Background, nil, bson.D{{"$inc", bson.D{{"x", 1}}}})
494+
assert.Equal(mt, err, mongo.ErrNilValue, "expected %v, got %v", mongo.ErrNilValue, err)
495+
})
496+
mt.RunOpts("found", noClientOpts, func(mt *mtest.T) {
497+
testCases := []struct {
498+
name string
499+
id interface{}
500+
}{
501+
{"objectID", primitive.NewObjectID()},
502+
{"string", "foo"},
503+
{"int", 11},
504+
}
505+
for _, tc := range testCases {
506+
mt.Run(tc.name, func(mt *mtest.T) {
507+
doc := bson.D{{"_id", tc.id}, {"x", 1}}
508+
_, err := mt.Coll.InsertOne(mtest.Background, doc)
509+
assert.Nil(mt, err, "InsertOne error: %v", err)
510+
511+
update := bson.D{{"$inc", bson.D{{"x", 1}}}}
512+
513+
res, err := mt.Coll.UpdateByID(mtest.Background, tc.id, update)
514+
assert.Nil(mt, err, "UpdateByID error: %v", err)
515+
assert.Equal(mt, int64(1), res.MatchedCount, "expected matched count 1, got %v", res.MatchedCount)
516+
assert.Equal(mt, int64(1), res.ModifiedCount, "expected modified count 1, got %v", res.ModifiedCount)
517+
assert.Nil(mt, res.UpsertedID, "expected upserted ID nil, got %v", res.UpsertedID)
518+
})
519+
}
520+
})
521+
mt.Run("not found", func(mt *mtest.T) {
522+
id := primitive.NewObjectID()
523+
doc := bson.D{{"_id", id}, {"x", 1}}
524+
_, err := mt.Coll.InsertOne(mtest.Background, doc)
525+
assert.Nil(mt, err, "InsertOne error: %v", err)
526+
527+
update := bson.D{{"$inc", bson.D{{"x", 1}}}}
528+
529+
res, err := mt.Coll.UpdateByID(mtest.Background, 0, update)
530+
assert.Nil(mt, err, "UpdateByID error: %v", err)
531+
assert.Equal(mt, int64(0), res.MatchedCount, "expected matched count 0, got %v", res.MatchedCount)
532+
assert.Equal(mt, int64(0), res.ModifiedCount, "expected modified count 0, got %v", res.ModifiedCount)
533+
assert.Nil(mt, res.UpsertedID, "expected upserted ID nil, got %v", res.UpsertedID)
534+
})
535+
mt.Run("upsert", func(mt *mtest.T) {
536+
doc := bson.D{{"_id", primitive.NewObjectID()}, {"x", 1}}
537+
_, err := mt.Coll.InsertOne(mtest.Background, doc)
538+
assert.Nil(mt, err, "InsertOne error: %v", err)
539+
540+
update := bson.D{{"$inc", bson.D{{"x", 1}}}}
541+
542+
id := "blah"
543+
res, err := mt.Coll.UpdateByID(mtest.Background, id, update, options.Update().SetUpsert(true))
544+
assert.Nil(mt, err, "UpdateByID error: %v", err)
545+
assert.Equal(mt, int64(0), res.MatchedCount, "expected matched count 0, got %v", res.MatchedCount)
546+
assert.Equal(mt, int64(0), res.ModifiedCount, "expected modified count 0, got %v", res.ModifiedCount)
547+
assert.Equal(mt, res.UpsertedID, id, "expected upserted ID %v, got %v", id, res.UpsertedID)
548+
})
549+
mt.Run("write error", func(mt *mtest.T) {
550+
id := "foo"
551+
update := bson.D{{"$set", bson.D{{"_id", 3.14159}}}}
552+
_, err := mt.Coll.InsertOne(mtest.Background, bson.D{{"_id", id}})
553+
assert.Nil(mt, err, "InsertOne error: %v", err)
554+
555+
_, err = mt.Coll.UpdateByID(mtest.Background, id, update)
556+
se, ok := err.(mongo.ServerError)
557+
assert.True(mt, ok, "expected ServerError, got %v", err)
558+
assert.True(mt, se.HasErrorCode(errorModifiedID), "expected error code %v, got %v", errorModifiedID, err)
559+
})
560+
mt.RunOpts("write concern error", mtest.NewOptions().Topologies(mtest.ReplicaSet), func(mt *mtest.T) {
561+
// 2.6 returns right away if the document doesn't exist
562+
id := "foo"
563+
update := bson.D{{"$set", bson.D{{"pi", 3.14159}}}}
564+
_, err := mt.Coll.InsertOne(mtest.Background, bson.D{{"_id", id}})
565+
assert.Nil(mt, err, "InsertOne error: %v", err)
566+
567+
mt.CloneCollection(options.Collection().SetWriteConcern(impossibleWc))
568+
_, err = mt.Coll.UpdateByID(mtest.Background, id, update)
569+
we, ok := err.(mongo.WriteException)
570+
assert.True(mt, ok, "expected error type %v, got %v", mongo.WriteException{}, err)
571+
assert.NotNil(mt, we.WriteConcernError, "expected write concern error, got %+v", we)
572+
})
573+
})
487574
mt.RunOpts("update many", noClientOpts, func(mt *mtest.T) {
488575
mt.Run("empty update", func(mt *mtest.T) {
489576
_, err := mt.Coll.UpdateMany(mtest.Background, bson.D{}, bson.D{})

0 commit comments

Comments
 (0)