问题描述
文档表示文档的大小由以下组成:
The docs says that the size of a document is composed of:
- 文档名称大小
- 每个字段名称的字符串大小之和
- 每个字段值的大小之和
- 另外32个字节
以下文档示例:
- 类型":个人"
- 完成":false
- 优先级":1
- 说明":"Learn Cloud Firestore"
具有147
的大小.
问题:
在计算文档的大小时,我还有什么需要注意的?也许一些元数据?由于使用此计算时 ,肯定有东西丢失.
When calculating the size of a document, is there anything else I should care of? Perhaps some metadata? Because when using this calculation, there's for sure something missing.
我上了这个课:
class Points {
public List<GeoPoint> geoPoints;
public Points() {}
public Points(List<GeoPoint> geoPoints) {
this.geoPoints = geoPoints;
}
}
这是我创建列表以及将其写入数据库的方式:
And this is how I create the list and how I write it to the database:
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());
}
}
});
使用示例进行
我的参考是:
Edit with example:
My reference is:
db.collection("points").document("geo");
- (6 +1)+(3 +1)+ 16 = 27
字段名称(数组)称为geoPoints
The field name (the array) is called geoPoints
- 9 +1 = 10
我将40,327个存储在该数组中
I store in that array 40,327
- 40,327 * 16 = 645232
每个文档还有32个额外的字节
There is an additional 32 additional bytes for each document
- 32
所以总共有:
总数:27 + 10 +645232 + 32 = 645301字节
Total: 27 + 10 + 645,232 + 32 = 645,301 bytes
在文档中没有任何地方指定数组中的每个元素的计数都超过其长度:
字段值大小
下表按类型显示了字段值的大小.
The following table shows the size of field values by type.
数组其值大小的总和
即使如此,如果我需要为每个位置添加一个字节(字节),例如,1代表一个数字,2代表两个数字,依此类推,另外还有一个1字节(在这种情况下)字符串,我应该在总数中添加230,850
.
Even so, if I need to add a byte (bytes) for every position, for example, 1 for a one digit number, 2 for a two digit number and so on and an additional 1 byte as it is in case of Strings, I should add 230,850
to the total.
因此,新的总数为645301 + 230,850 = 876,153.
So it makes a new total of 645,301 + 230,850 = 876,153.
这是允许的最大值.添加40,328,将被拒绝.
This is the maximum allowed. Adding 40,328, will be rejected.
无论如何,它再次小于小于允许的最大1,048,576
.
Anyway it is again less than the maximum 1,048,576
allowed.
推荐答案
TL; DR
最初的问题不涉及Geopoints,但随着更多的讨论发生,这才是最终目标.问题不是Firestore Documents无法保存1Mb数据(因为它们可以如下所示),而是真正的问题是OP如何计算他们想要存储的数据量.
The original question did not involve Geopoints but as more discussion took place that was the ultimate goal. The issue is not that Firestore Documents can't hold 1Mb of data (because they can as clearly shown below) but the actual issue is how the OP is calculating how much data they want to store.
Geopoint占用16个字节,但还有其他计算应添加到其中.因此,这里是计算文档大小的摘要
A Geopoint takes 16 bytes but there is also the rest of the calculation that should be added in. So here's a summary to calculate the size of a document
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
所以假设有1000个地理点
So suppose there are 1000 geopoints
8 +(字节数,取决于字段名称的长度)+(16 *#个地理点数)+ addl大小
8 + (bytes depending on the field name length) + (16 * # of geopoints) + addl Size
因此,正如您所看到的,讨论的不是围绕一个文档将容纳多少数据,而是关于如何计算一个地理点的文档大小.
So as you can see, the discussion is not around how much data a document will hold but about how the document size for a geopoint is calculated.
快速计算
var s = ""
for i in 0..<10000 {
s += String(i)
}
print(s.count)
显示,如果您要存储10000个Geopoint,则仅字段名就可以使用38890字节.
shows that if you want to store 10000 Geopoints, 38890 bytes goes just to field names alone.
讨论
此答案显示了如何计算Firestore文档的大小以及用于演示如何将大小为1Mb的文件(在这种情况下为图像)上载到Firestore文档的代码.
This answer shows how to calculate the size of a Firestore document as well as the code to demonstrate how a file (an image in this case) of size 1Mb can be uploaded to a Firestore document.
请注意,这不是在实际使用中应做的事情! -图像和文件应存储在存储设备中,而不是Firestore中,因此请以这种情况为例.
Note that this is NOT how it should be done in real world use! - images and files should be stored in Storage, not Firestore, so take this as an example case.
另外要注意的是,存储最大程度地容纳文档容量的数据集可能会影响整体性能,并否定查询或排序该数据服务器端的能力,这给应用程序资源带来了更多压力.如果担心每读写次数的成本,我建议您查看实时数据库,因为成本是每笔数据量的费用,而不是每笔读写的费用.
An additional note that storing datasets that max out the capacity of a document may hinder overall performance and negates the ability to query or sort that data server side which puts a lot more strain on the apps resources. If there is concern about cost per number of writes/reads, I suggest looking at the Real Time Data Base as the costs are per amount of data, not reads/writes.
首先,我们从一个名为Mountain的1Mb jpg开始
First we start with a 1Mb jpg called Mountain
要计算实际上传的数据量,我们使用Firebase中的以下内容存储和计算
To calculate the actual amount of data being uploaded, we use the following from the Firebase Storage and Calculations
文档的大小是以下各项的总和:
The size of a document is the sum of:
- 文档名称大小
- 每个字段名称的字符串大小之和
- 每个字段值的大小之和(在我们中只有一个字段
这个例子) - 另外32个字节
- The document name size
- The sum of the string size of each field name
- The sum of the size of each field value (we have only one field in
this example) - 32 additional bytes
在以下代码中,文档名称为"mountain_image",即14,字段名称为"imageData" 9,该字段值的大小计算(如下所示)加上32个字节.
In the following code, the document name is 'mountain_image' which is 14, the field name is 'imageData' 9, the size of the field value is calculated (shown below) plus 32 bytes.
对于此示例,我已将1Mb图像拖到我的App捆绑包中.这是(macOS)代码,可读取该图像,将其转换为Firestore的NSData类型并上传文件.
For this example, I've dragged the 1Mb image into my App bundle. Here's the (macOS) code that reads that image, converts it to a NSData type for Firestore and uploads the file.
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")
})
}
控制台的输出是这个
allowed size: 1048487
total size: 1040221
upload success
可以看出,总大小刚好在Firestore文档中允许的大小以下.
So as can be seen, the total size is just under the allowed size in a Firestore document.
总而言之,此代码将1Mb文件上传到Firestore文档
为完整起见,这是读取该数据对象,转换回图像并在UI中显示的代码
For completeness, here's the code that reads back that data object, converts back to an image and displays in the UI
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
}
})
}
请记住,文本字符串的大小是UTF-8编码的字节数+ 1,因此"Hello"将是6个总数,即5 + 1
Keep in mind that Text Strings sizes are the number of UTF-8 encoded bytes + 1 so 'Hello' would be 6 total, 5 + 1
OP添加了一些有关存储Geopoints的附加信息. Geopoint是Firestore中的一种特定数据类型,需要一个字段来存储Geopoint.尝试在单个字段中存储多个地理位置是不可能的.
The OP added some additional information about storing Geopoints. A Geopoint is a specific data type in Firestore and requires a single field to store a geopoint. Attempting to store multiple geopoints in a single field is not an option.
话虽如此,如果您要存储1Mb的Geopoint,仍然可以完成.
That being said, if you want to store 1Mb of geopoints, it can still be done.
这里有一些数学运算:文档中允许的总字节为1048487,如果每个地理点使用16个字节,快速划分表明可以存储大约65530个价值的地理点数据.
Here's some math: the total bytes allowed in a document is 1048487 and if each geopoint uses 16 bytes, quick division shows that approximately 65530 worth of geopoint data can be stored.
因此,如果我可以上传65530字节,则表明文档可以容纳大约1Mb的数据.正确的?这是执行此操作的代码
So if I can upload 65530 bytes then it shows that a document can hold approximately 1Mb of data. Right? Here's the code that does that
以下代码创建了将近65530个地理位置,并将其转换为字符串并将其存储在单个Firestore文档中.
The following code creates almost 65530 geopoints, converts them to a string and stores them in a single Firestore document.
func uploadGeopoints() {
var geoArray = [GeoPoint]()
let point = GeoPoint(latitude: 1.0, longitude: 1.0)
for i in 0..<65530 {
geoArray.append(point)
}
let geoString = geoArray.map { String("\($0.latitude)\($0.longitude)") }
let combinedString = geoString.joined()
let geoCollection = self.db.collection("geoStrings")
let thisGeoString = geoCollection.document()
let dict:[String: Any] = ["geoString": combinedString]
thisGeoString.setData(dict, completion: { error in
if let err = error {
print(err.localizedDescription)
return
}
print("upload success")
})
}
这篇关于Firestore文档的确切大小是多少?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!