The docs says that the size of a document is composed of:
- document name size
- The sum of the string size of each field name
- The su
TL;DR
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.
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
So suppose there are 1000 geopoints
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.
quick calculation
var s = ""
for i in 0..<10000 {
s += String(i)
}
print(s.count)
shows that if you want to store 10000 Geopoints, 38890 bytes goes just to field names alone.
Discussion
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.
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.
First we start with a 1Mb jpg called Mountain
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:
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.
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")
})
}
the output to console is this
allowed size: 1048487
total size: 1040221
upload success
So as can be seen, the total size is just under the allowed size in a Firestore document.
To summarize, this code uploads a 1Mb file to a Firestore Document
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
}
})
}
Keep in mind that Text Strings sizes are the number of UTF-8 encoded bytes + 1 so 'Hello' would be 6 total, 5 + 1
EDIT:
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.
That being said, if you want to store 1Mb of geopoints, it can still be done.
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.
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
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")
})
}