docs说文档的大小由以下组成:
- 文档名称大小
- 每个字段名称的字符串大小之和
- 每个字段值的大小之和
- 另外32个字节
以下文档示例:
大小为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");
字段名称(数组)称为geoPoints
我将40,327个存储在该数组中
每个文档还有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
。
答案 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开始
要计算实际上传的数据量,我们使用Firebase Storage and Calculations
中的以下内容文档的大小是以下各项的总和:
在以下代码中,文档名称为“ 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
}
})
}