Add unique values to my array in Parse Server (swift 3) - ios

My Parse Server has a class called "BooksAddedByUser", which has 3 columns:
objectId
user - contains the username of the PFUser.current()
ISBNArray - the ISBN of books added by the user
I would like to add the newly added bookNumber into the ISBNArray only if it doesn't exist in the that array yet. However, whenever I run my code below, it creates new objectIds with the same username in the class "BooksAddedByUser". And it also doesn't check if the bookNumber already exists. I'm not sure what's going on honestly.
let booksAddedByUser = PFObject(className: "BooksAddedByUser")
booksAddedByUser["user"] = PFUser.current()?.username
let query = PFQuery(className: "BooksAddedByUser")
query.whereKey("ISBNArray", contains: bookNumber)
query.findObjectsInBackground { (objects, error) in
if error != nil {
print(error)
} else {
print(self.bookNumber)
if let objects = objects {
for object in objects {
print("book is already added i think")
}
}
}
}
booksAddedByUser.addObjects(from: [bookNumber], forKey: "ISBNArray")
booksAddedByUser.saveInBackground { (success, error) in
if error != nil {
print("error saving new book")
} else {
print("new book saved!")
}
}
EDIT w/ new code:
let booksAddedByUser = PFObject(className: "BooksAddedByUser")
booksAddedByUser["user"] = PFUser.current()?.username
let query = PFQuery(className: "BooksAddedByUser")
query.findObjectsInBackground { (objects, error) in
if error != nil {
print(error)
} else {
print(self.bookNumber)
if let objects = objects {
if objects.contains(bookNumber) {
print("book exists")
}
}
}
}
booksAddedByUser.addObjects(from: [bookNumber], forKey: "ISBNArray")
booksAddedByUser.saveInBackground { (success, error) in
if error != nil {
print("error saving new book")
} else {
print("new book saved!")
}
}

You can check if an object exits in array by using this:
if arrObjects.contains(where: { $0.bookNumberPropertyName == "bookNumber" }) {
print("Book exists")
}

Related

When talking to Parse server (using Swift on iOS), why PFFileObject keeps returning nil?

Why does PFFileObject keeps giving me an error like Foundation._GenericObjCError.nilError and if I use PFFileObject(name:data:) to create a file object, I will get nil.
My code looks like:
func uploadImageFileToParseServer(image: UIImage, uid: String) {
guard let imageData = image.pngData() else {
UILogger.error("Null imageData")
return
}
UILogger.log("creating imageFile using \(uid) and \(imageData) under name \(uid)-img.png")
let unwrappedImageFile = try? PFFileObject(name: "\(uid)-img.png", data: imageData, contentType: "image/png")
unwrappedImageFile?.saveInBackground { (result, error) in
if let error = error{
UILogger.error("\(String(describing: error))")
} else {
let query = PFQuery(className: "User")
UILogger.log("Saving to User with uid \(uid)")
query.whereKey("objectId", equalTo: uid)
query.findObjectsInBackground(block: { (objects, error) in
if let user = objects {
for object in user {
UILogger.log("User \(uid) found. Updating his/her avatar column now")
object["avatar"] = unwrappedImageFile
object.saveInBackground { isSuccessful, error in
if !isSuccessful {
UILogger.error("Error in updating User - \(error.debugDescription)")
}
}
}
}
})
}
}
}

How can I delete a Firestore field, using whereField?

I'm trying to delete a field within a document, when the field "uid" matches the Current User's ID. I'm pretty stuck on this, and would appreciate any help. I detail, below, my code and how my database is set up.
#IBAction func deleteAccountButtonIsTapped(_ sender: Any) {
let db = Firestore.firestore()
let userID = Auth.auth().currentUser?.uid
let username = usernameTextField.placeholder
Auth.auth().currentUser?.delete(completion: { (error) in
if error != nil {
print("ERROR MAIN SETTINGS 136")
} else {
db.collection("FollowerList").whereField("uid", isEqualTo: userID!).getDocuments { (snapshot, error) in
for snapshot in snapshot?.documents {
}
}
}
}
)}
My Database has a collection "FollowerList", with documents named with the User's UID. Within these documents is a "uid" field, with the value of the User's UID.
Any help would be massively appreciated.
This should do the Job:
func deleteAccountButtonIsTapped(_ sender: Any) {
let db = Firestore.firestore()
let userID = Auth.auth().currentUser?.uid
let username = usernameTextField.placeholder
Auth.auth().currentUser?.delete(completion: { (error) in
if error != nil {
print("ERROR MAIN SETTINGS 136")
} else {
db.collection("FollowerList").whereField("uid", isEqualTo: userID!).getDocuments { (snapshot, error) in
if let snapshot = snapshot?.documents {
for doc in snapshot {
//Do delete
db.collection("FollowerList").document(doc.documentID).updateData([
"fieldToDelete": FieldValue.delete(),
]) { err in
if let err = err {
print("Error updating document: \(err)")
} else {
print("Document successfully updated")
}
}
}
}
}
}
}
)}
One would think it could work like this:
But it doesn't as a value of type 'QueryDocumentSnapshot' has no member 'updateData'.
func deleteAccountButtonIsTapped(_ sender: Any) {
let db = Firestore.firestore()
let userID = Auth.auth().currentUser?.uid
let username = usernameTextField.placeholder
Auth.auth().currentUser?.delete(completion: { (error) in
if error != nil {
print("ERROR MAIN SETTINGS 136")
} else {
db.collection("FollowerList").whereField("uid", isEqualTo: userID!).getDocuments { (snapshot, error) in
if let snapshot = snapshot?.documents {
for doc in snapshot {
// How one would think it works but it doesnt
doc.updateData([
"capital": FieldValue.delete(),
]) { err in
if let err = err {
print("Error updating document: \(err)")
} else {
print("Document successfully updated")
}
}
}
}
}
}
}
)}
See this page for further information:
https://firebase.google.com/docs/firestore/manage-data/delete-data#swift

Check if a row exists in Parse, if it does update a column in the row instead of creating a new row each time. Swift

I have a className called SearchPreferences and it is empty until the current user makes a selection. When they make a selection a new row is created in this class with the updated info. The problem is if the user goes back and makes another selection I am creating a new row again instead of just updating the column. Here is the code that is saving the info but on a new row:`
let music = PFObject(className: "SearchPreferences")
music["music"] = table_data[indexPath.row]
// music["user"] = PFUser.currentUser()!.username!
music.saveInBackgroundWithBlock{(success, error) -> Void in
if error == nil {
music.saveInBackground()
print("success")
} else {
print("error")
}
}
`
All I can find is SQL and PHP online help. I tried the code below to call objId but I don't know it as its empty so it returns the below error.
The code below returns the error
No results matched the query. (Code: 101, Version: 1.7.5)
let query = PFQuery(className:"SearchPreferences")
query.getObjectInBackgroundWithId("musicSearch") {
(searchPreference: PFObject?, error: NSError?) -> Void in
if error != nil {
if let searchPreference = searchPreference {
searchPreference["musicSearch"] = self.table_data[indexPath.row]
searchPreference.saveInBackground()
if error == nil {
query.whereKeyDoesNotExist("musicSearch")
let searchPreference = PFObject(className: "SearchPreferences")
searchPreference["musicSearch"] = self.table_data[indexPath.row]
searchPreference.saveInBackgroundWithBlock{(success, error) -> Void in
The same can be send for this attempt:
var query = PFQuery(className:"SearchPreferences")
query.getObjectInBackgroundWithId("musicSearch") {
(searchPreference: PFObject?, error: NSError?) -> Void in
if error != nil {
print(error)
} else if let searchPreference = searchPreference {
searchPreference["musicSearch"] = self.table_data[indexPath.row]
searchPreference.saveInBackground()
}
}
I am trying to figure out how to either before running the query check if it is empty and if it is carry out my initial query. Parse docs only tell you how to save to classname _User not a second classname.
Here is an example on duplicated record update from parse community, you can use the same method to apply it with your code.
let adventureQuery = PFQuery(className: “Class Name“)
adventureQuery.limit = 1000
adventureQuery.addDescendingOrder(“Column Name”)
adventureQuery.getFirstObjectInBackground { (Success, error) in
Success?.setValue(self.toolsTitleTextField.text, forKey: "toolsTitle")
Success?.setValue(self.locationTextField.text, forKey: "location")
Success?.setValue(self.dateTextField.text, forKey: "createrDate")
Success?.saveInBackground(block: { (success, error) in
if (success){
Utility.showAlert("Success!", message: "Insert SuccessFully", viewController: self)
}
else{
let viewController = self.storyboard?.instantiateViewController(withIdentifier: "") as! ViewController
self.navigationController?.pushViewController(viewController, animated: true)
}
})
}

How to query parse for a specific item and prevent duplicates from being saved

I am trying to prevent duplicated items from being duplicated by querying for two objects a user and an item. If they exist then do not duplicate but if it doesn't exist then make an instance of it. I know that it keeps running and makes several duplicates depending on number of items present in parse. Does anyone know how to prevent it from duplicating those values?
func addUserToItem(userID:String,myItemID:String,currCommit:Float) {
let query = PFQuery(className: "UserToItem")
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if error != nil {
print("Got an error here")
} else {
print(objects)
for object in objects! {
print("ok")
guard let userInformation = object.objectForKey("username") as? String else {
print("didnt work")
return
}
guard let itemInformation = object.objectForKey("currentItem") as? String else {
print("didnt work2")
return
}
var isThere = false
if (userInformation == userID) && (itemInformation == myItemID) {
print("It exists")
isThere = true
}
if !isThere {
print("it worked")
let myProduct = PFObject(className: "UserToItem")
myProduct.setObject(userID, forKey: "username")
myProduct.setObject(myItemID, forKey: "currentItem")
myProduct.setObject(currCommit, forKey: "UserCommit")
myProduct.setObject(true, forKey: "Viewed")
myProduct.saveInBackground()
isThere = true
}
}
}
})
}
You can used NSSet for store unique objects.
I don't mean to be answering my own question, but I figured it out. It is working right now as planned. Here is my code. It works right now, but then again I though my earlier solutions worked too except they didn't afterwards. Does this look good to everyone? Would this give me a headache later on?
func addUserToItem(userID:String,myItemID:String,currCommit:Float) {
let query = PFQuery(className: "UserToItem")
query.whereKey("username", equalTo: userID)
query.whereKey("currentItem", equalTo: myItemID)
query.getFirstObjectInBackgroundWithBlock { (object, error) -> Void in
if error != nil {
let myProduct = PFObject(className: "UserToItem")
myProduct.setObject(userID, forKey: "username")
myProduct.setObject(myItemID, forKey: "currentItem")
myProduct.setObject(currCommit, forKey: "UserCommit")
myProduct.setObject(true, forKey: "Viewed")
myProduct.saveInBackground()
} else {
print("it exists")
}
}
}

Write to a Parse column after query - Swift

How can I use a query to find the currentUser from a Parse Class and then write data into that user columns?
var query = PFQuery(className:"User")
query.whereKey("objectId", equalTo:PFUser.currentUser()!)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
println("Successfully retrieved \(objects!.count) scores.")
// Do something with the found objects
if let objects = objects as? [PFObject] {
for object in objects {
println(object.objectId)
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
Change this line
query.whereKey("objectId", equalTo:PFUser.currentUser()!)
To:
query.whereKey("objectId", equalTo:PFUser.currentUser().objectId)
And also if you are querying from the parse user class it should be _User not User
To Only save data
var ObjectToSave = PFObject(className: "_User")
ObjectToSave["raw"] = "whateveryoulike"
ObjectToSave["UserId"] = PFUser.currentUser()?.objectId // this piece of code is when you create a new class
ObjectToSave.saveInBackgroundWithBlock { (success:Bool, error:NSError?) -> Void in
if error == nil{
println("data was saved")
}
else
{
println("error")
}
}
}
I don't think it is a good idea to save other data into the _User class, you should leave this class for the login or sign up. You should create a new class then save all new data with the userid...
you don't need to query for the current user.
Use this
var user = PFUser.currentUser()
user["one"] = "whateveryoulike"
user["two"] = "whateveryoulike"
user.saveInBackgroundWithBlock { (success:Bool, error:NSError?) -> Void in
if error == nil{
println("data was saved")
}
else
{
println("error")
}
}
}

Resources