Skip to content

Commit afd796b

Browse files
author
Divjot Arora
authored
GODRIVER-1381 Add GridFS examples (#272)
1 parent 499dea5 commit afd796b

File tree

4 files changed

+216
-2
lines changed

4 files changed

+216
-2
lines changed

mongo/gridfs/bucket.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,19 @@ func (b *Bucket) OpenUploadStreamWithID(fileID interface{}, filename string, opt
137137
}
138138

139139
// UploadFromStream creates a fileID and uploads a file given a source stream.
140+
//
141+
// If this upload requires a custom write deadline to be set on the bucket, it cannot be done concurrently with other
142+
// write operations operations on this bucket that also require a custom deadline.
140143
func (b *Bucket) UploadFromStream(filename string, source io.Reader, opts ...*options.UploadOptions) (primitive.ObjectID, error) {
141144
fileID := primitive.NewObjectID()
142145
err := b.UploadFromStreamWithID(fileID, filename, source, opts...)
143146
return fileID, err
144147
}
145148

146149
// UploadFromStreamWithID uploads a file given a source stream.
150+
//
151+
// If this upload requires a custom write deadline to be set on the bucket, it cannot be done concurrently with other
152+
// write operations operations on this bucket that also require a custom deadline.
147153
func (b *Bucket) UploadFromStreamWithID(fileID interface{}, filename string, source io.Reader, opts ...*options.UploadOptions) error {
148154
us, err := b.OpenUploadStreamWithID(fileID, filename, opts...)
149155
if err != nil {
@@ -191,6 +197,9 @@ func (b *Bucket) OpenDownloadStream(fileID interface{}) (*DownloadStream, error)
191197

192198
// DownloadToStream downloads the file with the specified fileID and writes it to the provided io.Writer.
193199
// Returns the number of bytes written to the steam and an error, or nil if there was no error.
200+
//
201+
// If this download requires a custom read deadline to be set on the bucket, it cannot be done concurrently with other
202+
// read operations operations on this bucket that also require a custom deadline.
194203
func (b *Bucket) DownloadToStream(fileID interface{}, stream io.Writer) (int64, error) {
195204
ds, err := b.OpenDownloadStream(fileID)
196205
if err != nil {
@@ -221,6 +230,9 @@ func (b *Bucket) OpenDownloadStreamByName(filename string, opts ...*options.Name
221230
}
222231

223232
// DownloadToStreamByName downloads the file with the given name to the given io.Writer.
233+
//
234+
// If this download requires a custom read deadline to be set on the bucket, it cannot be done concurrently with other
235+
// read operations operations on this bucket that also require a custom deadline.
224236
func (b *Bucket) DownloadToStreamByName(filename string, stream io.Writer, opts ...*options.NameOptions) (int64, error) {
225237
ds, err := b.OpenDownloadStreamByName(filename, opts...)
226238
if err != nil {
@@ -231,6 +243,9 @@ func (b *Bucket) DownloadToStreamByName(filename string, stream io.Writer, opts
231243
}
232244

233245
// Delete deletes all chunks and metadata associated with the file with the given file ID.
246+
//
247+
// If this operation requires a custom write deadline to be set on the bucket, it cannot be done concurrently with other
248+
// write operations operations on this bucket that also require a custom deadline.
234249
func (b *Bucket) Delete(fileID interface{}) error {
235250
// delete document in files collection and then chunks to minimize race conditions
236251

@@ -256,6 +271,9 @@ func (b *Bucket) Delete(fileID interface{}) error {
256271
}
257272

258273
// Find returns the files collection documents that match the given filter.
274+
//
275+
// If this download requires a custom read deadline to be set on the bucket, it cannot be done concurrently with other
276+
// read operations operations on this bucket that also require a custom deadline.
259277
func (b *Bucket) Find(filter interface{}, opts ...*options.GridFSFindOptions) (*mongo.Cursor, error) {
260278
ctx, cancel := deadlineContext(b.readDeadline)
261279
if cancel != nil {
@@ -287,6 +305,9 @@ func (b *Bucket) Find(filter interface{}, opts ...*options.GridFSFindOptions) (*
287305
}
288306

289307
// Rename renames the stored file with the specified file ID.
308+
//
309+
// If this operation requires a custom write deadline to be set on the bucket, it cannot be done concurrently with other
310+
// write operations operations on this bucket that also require a custom deadline
290311
func (b *Bucket) Rename(fileID interface{}, newFilename string) error {
291312
ctx, cancel := deadlineContext(b.writeDeadline)
292313
if cancel != nil {
@@ -313,6 +334,9 @@ func (b *Bucket) Rename(fileID interface{}, newFilename string) error {
313334
}
314335

315336
// Drop drops the files and chunks collections associated with this bucket.
337+
//
338+
// If this operation requires a custom write deadline to be set on the bucket, it cannot be done concurrently with other
339+
// write operations operations on this bucket that also require a custom deadline
316340
func (b *Bucket) Drop() error {
317341
ctx, cancel := deadlineContext(b.writeDeadline)
318342
if cancel != nil {

mongo/gridfs/doc.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (C) MongoDB, Inc. 2017-present.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
// not use this file except in compliance with the License. You may obtain
5+
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
7+
// Package gridfs provides a MongoDB GridFS API. See https://docs.mongodb.com/manual/core/gridfs/ for more
8+
// information about GridFS and its use cases.
9+
//
10+
// Buckets
11+
//
12+
// The main type defined in this package is Bucket. A Bucket wraps a mongo.Database instance and operates on two
13+
// collections in the database. The first is the files collection, which contains one metadata document per file stored
14+
// in the bucket. This collection is named "<bucket name>.files". The second is the chunks collection, which contains
15+
// chunks of files. This collection is named "<bucket name>.chunks".
16+
//
17+
// Uploading a File
18+
//
19+
// Files can be uploaded in two ways:
20+
// 1. OpenUploadStream/OpenUploadStreamWithID - These methods return an UploadStream instance. UploadStream
21+
// implements the io.Writer interface and the Write() method can be used to upload a file to the database.
22+
//
23+
// 2. UploadFromStream/UploadFromStreamWithID - These methods take an io.Reader, which represents the file to
24+
// upload. They internally create a new UploadStream and close it once the operation is complete.
25+
//
26+
// Downloading a File
27+
//
28+
// Similar to uploads, files can be downloaded in two ways:
29+
// 1. OpenDownloadStream/OpenDownloadStreamByName - These methods return a DownloadStream instance. DownloadStream
30+
// implements the io.Reader interface. A file can be read either using the Read() method or any standard library
31+
// methods that reads from an io.Reader such as io.Copy.
32+
//
33+
// 2. DownloadToStream/DownloadToStreamByName - These methods take an io.Writer, which represents the download
34+
// destination. They internally create a new DownloadStream and close it once the operation is complete.
35+
package gridfs

mongo/gridfs/gridfs_examples_test.go

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright (C) MongoDB, Inc. 2017-present.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
// not use this file except in compliance with the License. You may obtain
5+
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
7+
package gridfs_test
8+
9+
import (
10+
"bytes"
11+
"context"
12+
"fmt"
13+
"io"
14+
"log"
15+
"time"
16+
17+
"go.mongodb.org/mongo-driver/bson"
18+
"go.mongodb.org/mongo-driver/bson/primitive"
19+
"go.mongodb.org/mongo-driver/mongo/gridfs"
20+
"go.mongodb.org/mongo-driver/mongo/options"
21+
)
22+
23+
func ExampleBucket_OpenUploadStream() {
24+
var fileContent []byte
25+
var bucket *gridfs.Bucket
26+
27+
// Specify the Metadata option to include a "metadata" field in the files collection document.
28+
uploadOpts := options.GridFSUpload().SetMetadata(bson.D{{"metadata tag", "tag"}})
29+
uploadStream, err := bucket.OpenUploadStream("filename", uploadOpts)
30+
if err != nil {
31+
log.Fatal(err)
32+
}
33+
defer func() {
34+
if err = uploadStream.Close(); err != nil {
35+
log.Fatal(err)
36+
}
37+
}()
38+
39+
// Use SetWriteDeadline to force a timeout if the upload does not succeed in 2 seconds.
40+
if err = uploadStream.SetWriteDeadline(time.Now().Add(2 * time.Second)); err != nil {
41+
log.Fatal(err)
42+
}
43+
44+
if _, err = uploadStream.Write(fileContent); err != nil {
45+
log.Fatal(err)
46+
}
47+
}
48+
49+
func ExampleBucket_UploadFromStream() {
50+
var fileContent []byte
51+
var bucket *gridfs.Bucket
52+
53+
// Specify the Metadata option to include a "metadata" field in the files collection document.
54+
uploadOpts := options.GridFSUpload().SetMetadata(bson.D{{"metadata tag", "tag"}})
55+
fileID, err := bucket.UploadFromStream("filename", bytes.NewBuffer(fileContent), uploadOpts)
56+
if err != nil {
57+
log.Fatal(err)
58+
}
59+
60+
fmt.Printf("new file created with ID %s", fileID)
61+
}
62+
63+
func ExampleBucket_OpenDownloadStream() {
64+
var bucket *gridfs.Bucket
65+
var fileID primitive.ObjectID
66+
67+
downloadStream, err := bucket.OpenDownloadStream(fileID)
68+
if err != nil {
69+
log.Fatal(err)
70+
}
71+
defer func() {
72+
if err := downloadStream.Close(); err != nil {
73+
log.Fatal(err)
74+
}
75+
}()
76+
77+
// Use SetReadDeadline to force a timeout if the download does not succeed in 2 seconds.
78+
if err = downloadStream.SetReadDeadline(time.Now().Add(2 * time.Second)); err != nil {
79+
log.Fatal(err)
80+
}
81+
82+
fileBuffer := bytes.NewBuffer(nil)
83+
if _, err := io.Copy(fileBuffer, downloadStream); err != nil {
84+
log.Fatal(err)
85+
}
86+
}
87+
88+
func ExampleBucket_DownloadToStream() {
89+
var bucket *gridfs.Bucket
90+
var fileID primitive.ObjectID
91+
92+
fileBuffer := bytes.NewBuffer(nil)
93+
if _, err := bucket.DownloadToStream(fileID, fileBuffer); err != nil {
94+
log.Fatal(err)
95+
}
96+
}
97+
98+
func ExampleBucket_Delete() {
99+
var bucket *gridfs.Bucket
100+
var fileID primitive.ObjectID
101+
102+
if err := bucket.Delete(fileID); err != nil {
103+
log.Fatal(err)
104+
}
105+
}
106+
107+
func ExampleBucket_Find() {
108+
var bucket *gridfs.Bucket
109+
110+
// Specify a filter to find all files with a length greater than 1000 bytes.
111+
filter := bson.D{
112+
{"length", bson.D{{"$gt", 1000}}},
113+
}
114+
cursor, err := bucket.Find(filter)
115+
if err != nil {
116+
log.Fatal(err)
117+
}
118+
defer func() {
119+
if err := cursor.Close(context.TODO()); err != nil {
120+
log.Fatal(err)
121+
}
122+
}()
123+
124+
type gridfsFile struct {
125+
Name string `bson:"filename"`
126+
Length int64 `bson:"length"`
127+
}
128+
var foundFiles []gridfsFile
129+
if err = cursor.All(context.TODO(), &foundFiles); err != nil {
130+
log.Fatal(err)
131+
}
132+
133+
for _, file := range foundFiles {
134+
fmt.Printf("filename: %s, length: %d\n", file.Name, file.Length)
135+
}
136+
}
137+
138+
func ExampleBucket_Rename() {
139+
var bucket *gridfs.Bucket
140+
var fileID primitive.ObjectID
141+
142+
if err := bucket.Rename(fileID, "new file name"); err != nil {
143+
log.Fatal(err)
144+
}
145+
}
146+
147+
func ExampleBucket_Drop() {
148+
var bucket *gridfs.Bucket
149+
150+
if err := bucket.Drop(); err != nil {
151+
log.Fatal(err)
152+
}
153+
}

mongo/gridfs/upload_stream.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ const UploadBufferSize = 16 * 1024 * 1024 // 16 MiB
2626
// ErrStreamClosed is an error returned if an operation is attempted on a closed/aborted stream.
2727
var ErrStreamClosed = errors.New("stream is closed or aborted")
2828

29-
// UploadStream is used to upload files in chunks.
29+
// UploadStream is used to upload a file in chunks. This type implements the io.Writer interface and a file can be
30+
// uploaded using the Write method. After an upload is complete, the Close method must be called to write file
31+
// metadata.
3032
type UploadStream struct {
3133
*Upload // chunk size and metadata
3234
FileID interface{}
@@ -55,7 +57,7 @@ func newUploadStream(upload *Upload, fileID interface{}, filename string, chunks
5557
}
5658
}
5759

58-
// Close closes this upload stream.
60+
// Close writes file metadata to the files collection and cleans up any resources associated with the UploadStream.
5961
func (us *UploadStream) Close() error {
6062
if us.closed {
6163
return ErrStreamClosed

0 commit comments

Comments
 (0)