Save multiple data with a loop in FirebaseDatabase - Swift IOS - ios

with my code I would save multiple data with a loop in my Firebase Database. I have used a while loop to save some strings in my Database but my app saves only the last book and I don't know how to fix this problem. Any ideas?
let refUsers = FIRDatabase.database().reference().child("Users").child("User" + tag_login).child(user_key).child("Books").child("Others")
let key = refUsers.childByAutoId().key
let multipleBooksValues = ["multipleBooks": "Yes", "read": "Yes"] as NSDictionary
refUsers.child(key).setValue(multipleBooksValues)
let refBooks = FIRDatabase.database().reference().child("Books").child("User's books").child(book_key)
var bookNumber = 0
let numberOfBooks = bookList.count
while bookNumber < numberOfBooks {
let book = bookList[bookNumber]
let values = ["book_key\(bookNumber)" : book.book_key!] as NSDictionary
refUsers.child(key).child("multipleBooksNumber").setValue(values)
refBooks.updateChildValues(["onGoingNegotiations" : "Yes", "other_user_key" : self.user_key, "other_tag_login": self.tag_login])
refUsers.child(key).child("multipleBooksNumber").observe(.value, with: { (snapshot) in
let numberChildren = Int(snapshot.childrenCount - 1)
if numberChildren == bookNumber{
bookNumber += 1
}
})
}
Thank you in advance.

Each next book in your loop is overwriting the previous book. The easiest way to prevent this is to call setValue() one level deeper in the tree:
while bookNumber < numberOfBooks {
let book = bookList[bookNumber]
refUsers.child(key).child("multipleBooksNumber/\(bookNumber)").setValue(book.book_key!)
}
Note though that the Firebase documentation and blog recommend against using arrays like this for storing data. Either store the books under their natural key:
refUsers.child(key).child("multipleBooksNumber/\(book.book_key!)").setValue(true)
Or store them under so-called push IDs:
refUsers.child(key).child("multipleBooksNumber").childByAutoId().setValue(book.book_key!);

Maybe the problem is that you save all books to the same path and they are being re-written one by another all the time, so only the last one is being saved in the end?
You specify your key once
let key = refUsers.childByAutoId().key
and then save all values to path
refUsers.child(key).child("multipleBooksNumber").setValue(values)

Related

Coredata relationships how make ordered collection or added in particular index in iOS swift

I am working with core-data relationships add the student in profile entities.
Profile and Student entities are multiple relationship with each others.
Profile entities for create students, it successfully created.
I want to add or append some information that profile entities through student entities its also added.
(Its Like: Profile entities have a array of dictionary of student entities )
But when in display in UItableview added info of student it display in unordered.
I want to display the added student should be display in last or first.
Coredata is unordered collection of set. how to make it order.
Also selected ordered Arrangement. its shows error students not be ordered.
How can achieve this. Help me
Here my code:
func create(record: ProfileModel) {
let cdProfile = CDProfile(context: PersistentStorage.shared.context)
cdProfile.emailID = record.emailID
cdProfile.gender = record.gender
cdProfile.getDate = record.getDate
cdProfile.id = record.id
if(record.toStudent != nil && record.toStudent?.count != 0){
var studentSet = Set<CDStudent>()
record.toStudent?.forEach({ (student) in
let cdStudent = CDStudent(context: PersistentStorage.shared.context)
cdStudent.activity = student.activity
cdStudent.currentPage = Int16(student.currentPage ?? 0)
cdStudent.getPercentage = student.getPercentage
studentSet.insert(cdStudent)
})
cdProfile.toStudent = studentSet
}
PersistentStorage.shared.saveContext()
}
#IBAction func saveBtnClick(_ sender: Any) {
let studentArr = StudentModel(_activity: "S-\(self.sectionString)", _studentComments: self.infotextView.text, _getPercentage: "-", _result: String(self.audioValueKey.count), _sectionID: self.sectionString, _sessionDate: self.convertedDate, _timeSpend: self.timeSpendStr, _currentPage: self.allPageNumber, _selectedValue: self.audioValueKey)
if let getStudentData = userProfileArr![indexNumber].toStudent?.count{
self.personArrCount = getStudentData
let getArr = userProfileArr![indexNumber].toStudent!
if getArr.count == 0{
}else{
for j in 0..<getArr.count{
self.student.append(getArr[j])
// self.student.insert(getArr[j], at: 0)
}
self.student.append(studentArr)
}
}else{
self.personArrCount = 0
self.student.append(studentArr)
print("student-empty",student)
}
let getProfileData = userProfileArr![indexNumber]
let updatePerson = ProfileModel(_id: selectedUserIndex!.id, _profileComments: getProfileData.profileComments!, _emailID: getProfileData.emailID!, _gender: getProfileData.gender!, _profileImage: getProfileData.profileImage!, _getDate: "NO", _studentDOB: getProfileData.studentDOB!, _studentName: getProfileData.studentName!, _toStudent: student)
print("student",self.student)
if(dataManager.update(record: updatePerson))
{
print("Update added")
}else{
print("Not-- added")
}
}
How can i fix this issue help me... Thanks advance.
first of all Core data only provides sorting on parent table only
if you wanna sort data in a subtable you can do as below
First you need to add a field named student_id(int16) in student table
Then you need to assign value as count + 1
As core data does not provide autoincrement field need to manage manually.
Follow the below code to sort data as last to first
// assume you have fetched profile in stud_profile var
if let student_list = stud_profile.toStudent as? Set<CDStudent> {
let arrStudents = Array(student_list).sorted(by: {$0.student_id > $1.student_id})
}
4.You can use arrStudents as it will return sorted [CDStudent]

ios firebase how to fetch multiple object inside collection?

I had a problem with firebase , i have 5 document IDs . I need to query those 5 documents , convert them in to object.
for oneID in allIDs {
self.db.collection("storecollection").document(oneID).getDocument {(snap,err) in
let oneobject = convertToObject(snap)
self.tempHolder.append(oneobject)
var newarray = [MyObjectClass]()
if allIDs.last == oneID {
// perform copy
for x in 0...(self.tempHolder.count -1){
newarray.append(self.tempHolder[x])
}
self.tempHolder.removeAll()
completion(newarray)
}
}
Something wrong with code above , the size of self.tempHolder always count = 1. (Only the last id fetched object exist) i have no idea how to make it right.
Whats the right way to fetch multiple document (with specifiedID) ???
There's a bit of extraneous code in the question so it's not exactly clear but it seems you want to iterate over an array of document keys, read each associated document and add properties to an array (or in your case create an object based on those properties and add it)
Here's a simple example reading in a series of posts, and appending the post text from each post in an array.
The structure is
posts //a collection
post_0
post_text: "A post"
post_1
post_text: "Another post"
post_2
post_text: "Cool post"
and the code to read in post_0 and post_2 and append the post text to an array
var postTextArray = [String]()
func readMultiplePosts() {
let postKeyArray = ["post_0", "post_2"]
for postKey in postKeyArray {
let docRef = self.db.collection("posts").document(postKey)
docRef.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
print("err fetchibng document")
return
}
guard let data = document.data() else {
print("doc was empty")
return
}
print("doc data: \(data)")
let post = document.get("post_text") as! String
self.postMsgArray.append(post)
}
}
}
then sometime later we want to print the post texts
for p in self.postMsgArray {
print(p)
}
and the output from console
A post
Cool post
While this solution works, a Firebaser will quickly point out that reading data like this in a tight loop is generally not recommended. It would be better to have some other correlation between the posts you want to read and then perform a query to read them in.

iterating an array to extract a value from firebase database in swift

might sound like a basic question--but I'm not seeing where I am going wrong..
I end up with either of these two scenarios:
I keep getting the error "Could not cast value of type __NSCFNumber to NSSTring". if I use extractedSku = skuList[i]!.value["sku"] as! String
If I remove as! String it saves it, but it isn't saved as a string. How do I get this to be saved as a string?
I have appended data from firebase into an array
skuArray = [AnyObject?]()
in viewDidLoad, I am iterating skuArray to extract the 'sku' and store into a variable.
var skuArray = [AnyObject?]()
var productDetailArray = [AnyObject?]()
data stored in Sku Array is:
[Optional(Snap (aRandomKey) {
active = 1;
sku = 888888;
})]
viewDidLoad:
let skuList = self.skuArray
for var i = 0; i < skuList.count ; ++i{
let extractedSku = skuList[i]!.value["sku"] as! String
// go into database and extract "products" details by sku
self.databaseRef.child("products/\(extractedSku)").observeEventType(.ChildAdded, withBlock: { (snapshot:FIRDataSnapshot) in
self.productDetailArray.append(snapshot)
})
Since the underlying type is NSNumber, use the stringValue property to get a String:
if let extractedSku = (skuList[i]?.value["sku"] as? NSNumber)?.stringValue {
// use extractedSku which is of type String
}

How to sort NSmutableArray from one of it indexes (lat lng coordinates) in Swift

I'm new in swift and I'd know how to do that in php, but I'm lost with all those dictionaries and I have no idea how to do that in swift 2. I've been googling for a while and didn't found what I need.
I'm parsing a jSon and storing it's values in an NSMutableDictionary in a loop and at the end of the loop I store the NSMutableDictionary in an NSMutableArray, so at the end I have an NSMutableArray with 43 elements, and each element have about 10 keys with their values. I need to sort those 43 elements from their "distance" key and sort them descending. I don't know if that is posible with this current approach. The value of the key "distance" is an int number (meters). I don't know if to use an NSMutableDictionary inside an NSMutable Array is the correct approach to do this but I'm using it because it is possible to have string keys, and not numbers indexes, so for me it's easier to access the key "distance" than the index 8...
First I load the jSon content:
private func parseJson(json : NSMutableArray, tableView : UITableView){
var c : Int = 0
for j in json {
var jsonValues = NSMutableDictionary()
//Create main value
guard let value = j.valueForKey("value")?.valueForKey("value")! else{
continue
}
//Get name
guard let Name : String = (value.valueForKey("Name")?.valueForKey("en") as? String) else {
continue
}
jsonValues["name"] = Name
//more code like this....
TableData.append(Name)
nsDict.insertObject(jsonValues, atIndex: c)
c += 1
}
this is my NSMutableArray content after being loaded:
And this is the code I have this far. Im trying to load the sorted content in a new array, but in this new array some keys are missing.
//Reorder Array by shop distance from user...
var sortDescriptor:NSSortDescriptor = NSSortDescriptor(key: "distance", ascending: true)
var sortedArray : NSArray = nsDict.sortedArrayUsingDescriptors([sortDescriptor])//Crashes
print(sortedArray)
I've managed to sort the array with this technique:
created a new class with for my array
import Foundation
class JsonArrayValues {
init(){
}
var name = String()
var distance = Float()
var lat = Float()
var lng = Float()
var openingTime = String()
var country = String()
var code = String()
var address = String()
var categories = String()
var city = String()
var type = String()
var brands = String()
}
I instantiated one before the loop:
var jsonArrData : [JsonArrayValues] = []
And another one inside the loop, in which I've added the values:
var c : Int = 0
for j in json {
var jsonValues : JsonArrayValues = JsonArrayValues()
//Get name
guard let Name : String = (value.valueForKey("Name")?.valueForKey("en") as? String) else {
continue
}
jsonValues.name = Name
//more code...
jsonArrData.append(jsonValues)
c += 1
}
And finally I've been able to call the function to reorder the array:
//Reorder Array by shop distance from user...
jsonArrData.sortInPlace({$0.distance < $1.distance})
One of your first steps in any non-trivial project really should be to spend some time looking around on github for tools that simplify your problem. In this case, you'd find there are so very many tools to simplify working with JSON in Swift. I'd suggest you look at EVReflection and Gloss particularly, although there are also many people who use SwiftyJSON.
You don't mention how you're accessing the network; you could look at AFNetworking or Alamofire. The latter also has AlamofireJsonToObjects to help.
I also found JSONExport to be incredibly useful.
You'd be spending a lot less time futzing with details as in this unfortunate question and more getting on with your larger goal.

How do I save dictionary (map object) to DynamoDB using Swift

I’m trying to save a dictionary to my DynamoDB table field using low-level API. I couldn’t figure out how to do it with object mapper. There is no example for this in AWS iOS documentation and I’ve tried to research and implement Java / .NET examples of the same subject unsuccessfully.
I want to update only the dictionary field in the row using updateExpression.
I stumbled to this question while searching for answer, but it didn't help: Best way to make Amazon AWS DynamoDB queries using Swift?
Here’s the function to update dynamoDB-table:
func saveMapToDatabase(hashKey:Int, rangeKey:Double, myDict:[Int:Double]){
let nsDict:NSDictionary = NSDictionary(dictionary: myDict)
var dictAsAwsValue = AWSDynamoDBAttributeValue();dictAsAwsValue.M = nsDict as [NSObject : AnyObject]
let updateInput:AWSDynamoDBUpdateItemInput = AWSDynamoDBUpdateItemInput()
let hashKeyValue:AWSDynamoDBAttributeValue = AWSDynamoDBAttributeValue();hashKeyValue.N = String(hashKey)
let rangeKeyValue:AWSDynamoDBAttributeValue = AWSDynamoDBAttributeValue(); rangeKeyValue.N = String(stringInterpolationSegment: rangeKey)
updateInput.tableName = "my_table_name"
updateInput.key = ["db_hash_key" :hashKeyValue, "db_range_key":rangeKeyValue]
//How I usually do low-level update:
//let valueUpdate:AWSDynamoDBAttributeValueUpdate = AWSDynamoDBAttributeValueUpdate()
//valueUpdate.value = dictAsAwsValue
//valueUpdate.action = AWSDynamoDBAttributeAction.Put
//updateInput.attributeUpdates = ["db_dictionary_field":valueUpdate]
//Using the recommended way: updateExpression
updateInput.expressionAttributeValues = ["dictionary_value":dictAsAwsValue]
updateInput.updateExpression = "SET db_dictionary_field = :dictionary_value"
self.dynamoDB.updateItem(updateInput).continueWithBlock{(task:BFTask!)->AnyObject! in
//do some debug stuff
println(updateInput.aws_properties())
println(task.description)
return nil
}
}
I solved it, the problem was that AWS requires dictionary keys to always be in the form of String, any other type is not allowed.
The working solution snippet:
...
updateInput.tableName = "my_table_name"
updateInput.key = ["db_hash_key" :hashKeyValue, "db_range_key":rangeKeyValue]
let dictionaryInRightFormat:NSDictionary = ["stringKey":dictAsAwsValue]
updateInput.expressionAttributeValues = updateInput.updateExpression = "SET db_dictionary_field = :stringKey"

Resources