Firestore文档的确切大小是多少?

时间:2020-04-08 18:48:14

标签: firebase firebase-realtime-database google-cloud-firestore

docs说文档的大小由以下组成:

  1. 文档名称大小
  2. 每个字段名称的字符串大小之和
  3. 每个字段值的大小之和
  4. 另外32个字节

以下文档示例:

  • “类型”:“个人”
  • “完成”:否
  • “优先级”:1
  • “说明”:“了解Cloud Firestore”

大小为147

问题:

在计算文档的大小时,我还有什么需要注意的?也许一些元数据?因为when using this calculation,所以肯定缺少某些东西。

我上了这个课:

class Points {
    public List<GeoPoint> geoPoints;

    public Points() {}

    public Points(List<GeoPoint> geoPoints) {
        this.geoPoints = geoPoints;
    }
}

这是我创建列表以及将其写入数据库的方式:

List<GeoPoint> geoPoints = new ArrayList<>();
for (int i = 1; i <= 40_327 ; i++) {
    geoPoints.add(new GeoPoint(11.22, 33.44));
}
DocumentReference geoRef = db.collection("points\geo");
geoRef.set(new Points(geoPoints)).addOnCompleteListener(new OnCompleteListener<Void>() {
    @Override
    public void onComplete(@NonNull Task<Void> task) {
        if (task.isSuccessful()) {
            Log.d("TAG", "geoPoints added successfully");
        } else {
            Log.d("TAG", task.getException().getMessage());
        }
    }
});

使用示例进行编辑:

我的参考是:

db.collection("points").document("geo");
  1. (6 +1)+(3 +1)+ 16 = 27

字段名称(数组)称为geoPoints

  1. 9 +1 = 10

我将40,327个存储在该数组中

  1. 40,327 * 16 = 645232

每个文档还有32个额外的字节

  1. 32

所以总共有:

总数:27 + 10 +645232 + 32 = 645301字节

There is nowhere specified in the docs that each element in the array counts more than his length

字段值大小

下表按类型显示了字段值的大小。

键入大小

数组其值大小的总和

即使如此,如果我需要为每个位置添加一个字节(字节),例如,1代表一个数字,2代表两个数字,依此类推,再加上一个1字节(在这种情况下)字符串,我应该在总数中添加230,850

因此,新的总数为645301 + 230,850 = 876,153。

这是允许的最大值。添加40,328,将被拒绝。

无论如何,它再次小于小于允许的最大值1,048,576

1 个答案:

答案 0 :(得分:1)

TL; DR

最初的问题不涉及Geopoints,但是随着更多的讨论发生,这才是最终目标。问题不是Firestore Documents无法保存1Mb的数据(因为它们可以如下所示),而是实际问题是OP如何计算要存储多少数据。

Geopoint占用16个字节,但还有其他计算应添加到其中。因此,这里是计算文档大小的摘要

strchr

所以假设有1000个地理点

8 +(字节数,取决于字段名称的长度)+(16 *#个地理点数)+ addl大小

因此,正如您所看到的,讨论的不是围绕文档将容纳多少数据,而是关于如何计算地理位置的文档大小。

快速计算

docNameSize = 8 //suppose it's called 'geoArray'
fieldNameSize = 5 // this is an array, so the first element name is 0 = 1 byte, 
                  // element 10 name would be two bytes
                  // up to 5 bytes for the higher numbers
geoPointSize = 16 * number of geopoints
addlSize = 32

显示,如果您要存储10000个Geopoint,则仅字段名就可以使用38890字节。

讨论

此答案显示了如何计算Firestore文档的大小以及用于演示如何将大小为1Mb的文件(在这种情况下为图像)上传到Firestore文档的代码。

请注意,这不是在实际使用中应该做的! -图像和文件应存储在存储设备中,而不是Firestore中,因此以这种情况为例。

需要额外注意的是,存储使文档容量最大的数据集可能会妨碍整体性能,并且会削弱查询或排序数据服务器端的能力,这给应用程序资源带来了更多压力。如果担心每读写次数的成本,我建议您查看实时数据库,因为成本是每笔数据量的费用,而不是每笔读写的费用。

首先,我们从一个名为Mountain的1Mb jpg开始

enter image description here

要计算实际上传的数据量,我们使用Firebase Storage and Calculations

中的以下内容

文档的大小是以下各项的总和:

  • 文档名称大小
  • 每个字段名称的字符串大小之和
  • 每个字段值的大小之和(我们在其中只有一个字段
    这个例子)
  • 另外32个字节

在以下代码中,文档名称为“ mountain_image”,即14,字段名称为“ imageData” 9,计算出的字段值大小(如下所示)加上32个字节。

对于此示例,我已将1Mb图像拖到我的App捆绑包中。这是(macOS)代码,可读取该图像,将其转换为Firestore的NSData类型并上传文件。

var s = ""
for i in 0..<10000 {
    s += String(i)
}
print(s.count)

控制台的输出是这个

func uploadImageToFirestre() {
    let image = NSImage(imageLiteralResourceName: "Mountain.jpeg")

    guard let asTiffData = image.tiffRepresentation else { return }
    let data = NSData(data: asTiffData)

    let imgRep = NSBitmapImageRep(data: data as Data)
    guard let jpgData = imgRep?.representation(using: NSBitmapImageRep.FileType.jpeg, properties:  [:]) else { return }

    let docNameSize = 14
    let fieldNameSize = 9
    let dataSize = jpgData.count
    let addlSize = 32

    let totalSize = docNameSize + fieldNameSize + dataSize + addlSize

    print("allowed size: \(1048487)")
    print("total size:   \(totalSize)")
    let imageCollection = self.db.collection("images")
    let thisImage = imageCollection.document("mountain_image")
    let dict:[String:Any] = ["imageData": jpgData]
    thisImage.setData(dict, completion: { error in
        if let err = error {
            print(err.localizedDescription)
            return
        }

        print("upload success")
    })
}

可以看出,总大小刚好在Firestore文档中允许的大小以下。

总而言之,此代码将1Mb文件上传到Firestore文档

为完整起见,这是读取该数据对象,转换回图像并在UI中显示的代码

allowed size: 1048487
total size:   1040221
upload success

请记住,文本字符串的大小是UTF-8编码的字节数+ 1,因此“ Hello”将是6个总数,即5 + 1

编辑:

OP添加了一些有关存储地理位置的附加信息。 Geopoint是Firestore中的一种特定数据类型,需要一个字段来存储Geopoint。尝试在单个字段中存储多个地理位置是不可能的。

话虽如此,如果您要存储1Mb的Geopoint,仍然可以完成。

这是一些数学运算:文档中允许的总字节为1048487,如果每个地理点使用16个字节,快速划分表明可以存储大约65530个价值的地理点数据。

因此,如果我可以上传65530字节,则表明文档可以容纳大约1Mb的数据。对?这是执行此操作的代码

以下代码创建了将近65530个地理位置,并将其转换为字符串并将其存储在单个Firestore文档中。

func readImageFromFirestore() {
    let imageCollection = self.db.collection("images")
    imageCollection.getDocuments(completion: { snapshot, error in
        if let err = error {
            print(err.localizedDescription)
            return
        }

        guard let snap = snapshot else { return }

        for doc in snap.documents {
            let imageData = doc.get("imageData") as! Data
            let image = NSImage(data: imageData)
            self.myImageView.image = image
        }

    })
}