TL; DR
Первоначальный вопрос не затрагивал геопоинтов, но по мере дальнейшего обсуждения это было конечной целью. Проблема не в том, что документы Firestore не могут содержать 1 МБ данных (потому что они могут, как ясно показано ниже), а в том, как операционный центр вычисляет, сколько данных они хотят сохранить.
Geopoint берет 16 байтов, но есть и остальные расчеты, которые следует добавить. Итак, вот сводная информация для расчета размера документа
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 геоинтессий
8 + (в байтах в зависимости от длины имени поля) + (16 * число географических точек) + addl Размер
Итак, как вы можете видеть, речь идет не о том, сколько данных будет содержать документ, а о том, как документ вычисляется размер для геопункта.
быстрый расчет
var s = ""
for i in 0..<10000 {
s += String(i)
}
print(s.count)
показывает, что если вы хотите сохранить 10000 геопоинтов, 38890 байт идет только на имена полей.
Обсуждение
Этот ответ показывает, как рассчитать размер документа Firestore, а также код, чтобы продемонстрировать, как файл (в данном случае изображение) размером 1M b можно загрузить в документ Firestore.
Обратите внимание, что это НЕ так, как это должно быть сделано в реальных условиях! - изображения и файлы должны храниться в хранилище, а не в Firestore, поэтому возьмем это в качестве примера.
Дополнительное примечание, что хранение наборов данных, которые максимально используют емкость документа, может снизить общую производительность и свести на нет возможность запрашивать или сортировать данные на стороне сервера данных, что значительно увеличивает нагрузку на ресурсы приложений. Если существует озабоченность по поводу стоимости количества операций записи / чтения, я предлагаю рассмотреть базу данных в реальном времени, поскольку затраты относятся к объему данных, а не к операциям чтения / записи.
Сначала мы начнем с jpg размером 1 МБ, который называется Гора
Чтобы рассчитать фактический объем загружаемых данных, мы используем следующее из базы данных Firebase Хранение и расчеты
Размер документа представляет собой сумму:
- Размер имени документа
- Сумма размера строки каждого имени поля
- сумма размера каждого значения поля (у нас есть только одно поле в
этом примере) - 32 дополнительных байта
В следующем коде имя документа равно 'mountain_image ', то есть 14, имя поля' imageData '9, вычисляется размер значения поля (показано ниже) плюс 32 байта.
Для этого примера я перетащил изображение размером 1 МБ в свое приложение расслоение. Вот код (macOS), который считывает это изображение, преобразует его в тип NSData для Firestore и загружает файл.
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.
Подводя итог, этот код загружает файл размером 1 МБ в документ 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
}
})
}
Имейте в виду, что размеры текстовых строк - это число байтов в кодировке UTF-8 + 1, поэтому Всего «Привет» будет 6, 5 + 1
РЕДАКТИРОВАТЬ:
ОП добавил дополнительную информацию о хранении географических точек. Geopoint - это определенный тип данных c в Firestore, для которого требуется одно поле для хранения геопозиции. Попытка сохранить несколько геопоинт в одном поле не вариант.
При этом, если вы хотите сохранить 1 Мб геоинт, это все равно можно сделать.
Вот немного математики: Общее количество разрешенных байтов в документе - 1048487, и если для каждого геопункта используется 16 байтов, быстрое разделение показывает, что могут быть сохранены данные о приблизительно 65530.
Поэтому, если я могу выгрузить 65530 байтов, то это показывает, что документ может хранить около 1 МБ данных. Правильно? Вот код, который делает это
Следующий код создает почти 65530 геопоинт, преобразует их в строку и сохраняет их в одном документе Firestore.
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")
})
}