Mongo-go-driver GridFS 元数据

Mongo-go-driver GridFS metadata

我为我工作的公司编写了一个聊天应用程序,并且使用了一段时间的 mgo 驱动程序。 现在我们将 mgo 重构为官方 mongo 驱动程序。 我已经实现了 GridFS 来处理聊天文件,因为它们并不大并且简化了工作。 以前的 mgo 驱动程序在保存文件时有一个数据列表,其中一个字段是 contentType(对吧?)

因此,在重构此任务中包含的大部分服务后,我注意到新的官方 mongo 驱动程序不会执行此操作??

所以我决定尝试手动添加此字段,但后来我不知道该怎么做?

尝试过 options.GridFSUpload().SetMetadata(metadata),但我不明白它的逻辑,而且互联网上关于在 GO 中工作的新 mongo 驱动程序的结果真的很少。

任何人都可以给我提示如何将自定义字段添加到文件文档中? 喜欢 contentType!!

非常感谢。

这是我尝试做的一个例子

// GridFSInsert -
func GridFSInsert(fileName string, data []byte, metadata ...bsonx.Elem) (primitive.ObjectID, error) {
    checkMongoConnection(false)
    var fileID primitive.ObjectID
    bucket, bucketErr := gridFs.NewBucket(
        Mongo.Client.Database(Mongo.DBName),
        options.GridFSBucket().SetName(gridFSColName),
    )
    if bucketErr != nil {
        return fileID, bucketErr
    }
    uploadStream, uploadStreamErr := bucket.OpenUploadStream(
        fileName,
        options.GridFSUpload().SetMetadata(metadata),
    )
    if uploadStreamErr != nil {
        return fileID, uploadStreamErr
    }
    defer uploadStream.Close()

    fileSize, writeErr := uploadStream.Write(data)
    if writeErr != nil {
        return fileID, writeErr
    }
    fileID = uploadStream.FileID
    log.Printf("Write file to DB was succesful, File size: %d", fileSize)

    return fileID, nil
}

抱歉,如果我遗漏了什么,因为我对 GO 的体验并不如我所愿。

感谢您的帮助

这里是 SetMetadata() 的例子。

opts := options.GridFSUpload()
opts.SetMetadata(bsonx.Doc{{Key: "content-type", Value: bsonx.String("application/json")}})
if ustream, err = bucket.OpenUploadStream("test.txt", opts); err != nil {
    t.Fatal(err)
}

这是full example

没有你试图理解的逻辑。在新的官方 mongo 驱动程序中找不到太多关于 contentType 的原因是因为 contentType has been deprecated in gridfs spec 早在编写驱动程序之前。

我必须承认 gridfs documentation 没有提到它。事实上官方 mongofiles cli 仍然使用旧格式。

规范直截了当:

Note: some older versions of GridFS implementations allowed applications to add arbitrary fields to the files collection document at the root level. New implementations of GridFS will not allow this, but must be prepared to handle existing files collection documents that might have additional fields.

如果你喜欢更详细的 official reasoning :

Why is contentType deprecated?

Most fields in the files collection document are directly used by the driver, with the exception of: metadata, contentType and aliases. All information that is purely for use of the application should be embedded in the 'metadata' document. Users of GridFS who would like to store a contentType for use in their applications are encouraged to add a 'contentType' field to the ‘metadata’ document instead of using the deprecated top-level ‘contentType’ field.

这有点道理。驱动程序从字面上遵循规范的措辞 - 除了在 metadata 之外,无法在任何地方创建 contentType 属性,但 Bucket.Find 仍将 return contentType 由 "older versions" 创建的文件。

从遗留 gridfs 到新格式的一次性转换可以很简单:

db.getCollection("fs.files").aggregate([
    {$addFields: { 
        "length" : {$toLong: "$length"},
        "metadata.contentType": { $ifNull: [ "$contentType", "$metadata.contentType" ] } 
    }},
    { $out : "fs.files" }
])

假设您的存储桶是默认存储桶 "fs",并且您不打算上传旧格式的文件。 如果你有足够的免费空间 space,out 到新的临时集合,验证它,然后重命名并不是一个糟糕的主意。

如果您出于任何原因必须支持旧版格式,您仍然可以直接访问 gridfs 集合:

// in your code snippet after
fileID = uploadStream.FileID

// update the document that represent uploaded file
files := db.Collection("fs.files")
updateResult, err := files.UpdateOne(
    context.Background(),
    bson.D{{"_id", fileID}},
    bson.D{{"$set", bson.D{{"contentType", contentType}}}},
)

其中 "fs" 是您的存储桶名称,contentType 是您要设置为 contentType 的字符串值。

请记住,"some older versions" 使用 int32 作为文件长度。新驱动程序期望它是 int64。 对于单独使用 *.fiiles 集合的类似查找的操作应该没问题,但可能会导致使用新的官方驱动程序下载此类文件时出现问题。