为了账号安全,请及时绑定邮箱和手机立即绑定

Mongo-go-driver GridFS 元数据

Mongo-go-driver GridFS 元数据

Go
慕丝7291255 2023-06-05 19:32:46
我为我工作的公司编写了一个聊天应用程序,并且我使用 mgo 驱动程序有一段时间了。现在我们将mgo重构为官方的mongo驱动。我已经实现了 GridFS 来处理聊天文件,因为它们并不大并且简化了工作。以前的 mgo 驱动程序在保存文件时有一个数据列表,其中一个字段是 contentType(对吧?)因此,在重构此任务中包含的大部分服务后,我注意到新的官方 mongo 驱动程序不执行此操作??所以我决定尝试手动添加此字段,但后来我到了我不明白该怎么做的地步?尝试过,options.GridFSUpload().SetMetadata(metadata)但我不明白它的逻辑,互联网上关于在 GO 中工作的新 mongo 驱动程序的结果真的很少。任何人都可以给我提示如何将自定义字段添加到文件文档中?喜欢内容类型!!真的很感激。这是我尝试做的一个例子// 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 的经验。谢谢你的帮助
查看完整描述

2 回答

?
qq_花开花谢_0

TA贡献1835条经验 获得超7个赞

您没有试图理解的逻辑。在新的官方 mongo 驱动程序中找不到太多关于 contentType 的原因是因为在编写驱动程序之前很久,contentType 在 gridfs 规范中就已被弃用。

我必须承认gridfs 文档没有提到它。事实上,官方的 mongofiles cli 仍然使用传统格式。

规范直截了当:

注意:一些旧版本的 GridFS 实现允许应用程序在根级别向文件集合文档添加任意字段。GridFS 的新实现将不允许这样做,但必须准备好处理可能具有附加字段的现有文件集合文档。

如果你喜欢更详细的官方推理:

为什么不推荐使用 contentType?

文件集合文档中的大多数字段都由驱动程序直接使用,但元数据、内容类型和别名除外。所有纯粹供应用程序使用的信息都应嵌入“元数据”文档中。鼓励希望存储 contentType 以在其应用程序中使用的 GridFS 用户将“contentType”字段添加到“元数据”文档,而不是使用已弃用的顶级“contentType”字段。

这有点道理。contentType驱动程序从字面上遵循规范的措辞——除了在 中,无法在任何地方创建属性metadata,但 Bucket.Find 仍将返回contentType由“旧版本”创建的文件。

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

db.getCollection("fs.files").aggregate([

    {$addFields: { 

        "length" : {$toLong: "$length"},

        "metadata.contentType": { $ifNull: [ "$contentType", "$metadata.contentType" ] } 

    }},

    { $out : "fs.files" }

])

假设您的存储桶默认为“fs”并且您不会以旧格式上传文件。如果您有足够的可用空间,那么创建新的临时集合、验证它然后重命名并不是一个糟糕的主意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 的字符串值。


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


查看完整回答
反对 回复 2023-06-05
?
茅侃侃

TA贡献1842条经验 获得超21个赞

这是一个例子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)

}

查看完整回答
反对 回复 2023-06-05
  • 2 回答
  • 0 关注
  • 139 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信