Firebase Cloud Firestore Security Rules for updateData FieldValue.delete() [swift] - swift

I'm removing the map element in the Test field.
Removing the "myID" key from the "Test"
self.db.collection("events").document("bkxREqn24JpdKYBLnBio").updateData([
"Test.myID": FieldValue.delete(),
]) { err in
if let err = err {
print("Error updating document: \(err)")
} else {
print("Document successfully updated")
}
}
How do I get the key of an item that I remove in the "security rules"?
That's not how it works:
service cloud.firestore {
match /databases/{database}/documents {
match /events/{eventID} {
allow write, update : if request.resource.data.Test.keys()[0] == "myID"
}
}
}
although this rule works for the record
self.db.collection("events").document("bkxREqn24JpdKYBLnBio").updateData([
"Test.myID": "MyText",
]) { err in
if let err = err {
print("Error updating document: \(err)")
} else {
print("Document successfully updated")
}
}

If I understand correctly, you want to only allow the write if the new document still contains myID value in the Test field, which is an array.
That'd be this in security rules:
allow write, update : if "myID" in request.resource.data.Test;
If you want to check if myID is being added, you'll compare request.resource.data with resource.data. So something like:
allow write, update : if "myID" in request.resource.data.Test
&& !("myID" in resource.data.Test);

Related

Retrieving Manually Inputted Data Firestore

Would it be possible to create documents in Firestore and then later reference it within swift/xcode/app? I want to manually add restaurant data into Firestore and then reference the data (city,type, phone number, etc.) within an app.
What do you recommend I do to be able to retrieve the manually typed out document entries?
Yes this is possible and not that hard to figure out when you look at the offical docs.
SDK IOS SETUP
https://firebase.google.com/docs/ios/setup
Getting started with firestorehttps://firebase.google.com/docs/firestore/quickstart#ios
Creating a new document in the collection "USERS"
// Add a new document with a generated ID
var ref: DocumentReference? = nil
ref = db.collection("users").addDocument(data: [
"first": "Ada",
"last": "Lovelace",
"born": 1815
]) { err in
if let err = err {
print("Error adding document: \(err)")
} else {
print("Document added with ID: \(ref!.documentID)")
}
}
Reading that data
db.collection("users").getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
print("\(document.documentID) => \(document.data())")
}
}
}
For referencing documents made by users you could safe the UserID to the firestore document and filter the documents in the app by Current user ID.
This is mostly used in apps.
I would also suggest to watch some videos from:
https://peterfriese.dev/
This will give you a clear understanding on what to do with the data you get back.

Golang mgo Fetching an item by label in a nested bson array

I'm having trouble finding objects in a nested array. I need to find home/away within league array which has an events array.
Example JSON:
{
"sportId":4,
"last":266178326,
"league":[
{
"id":423,
"name":"Germany - Bundesliga",
"events":[
{
"id":1125584543,
"starts":"2020-06-07T17:00:00Z",
"home":"SC Rasta Vechta",
"away":"EnBW Ludwigsburg",
"rotNum":"2601",
"liveStatus":0,
"status":"I",
"parlayRestriction":0,
"altTeaser":false,
"resultingUnit":"Regular"
},
{
"id":1125585441,
"starts":"2020-06-10T18:30:00Z",
"home":"Ratiopharm Ulm",
"away":"Crailsheim Merlins",
"rotNum":"2617",
"liveStatus":0,
"status":"I",
"parlayRestriction":0,
"altTeaser":false,
"resultingUnit":"Regular"
}
]
},
{
"id":268,
"name":"ABA - Adriatic League",
"events":[
{
"id":1122419811,
"starts":"2020-05-07T19:34:00Z",
"home":"Test 1(Do Not Wager)",
"away":"Test 2(Do Not Wager)",
"rotNum":"999998",
"liveStatus":0,
"status":"I",
"parlayRestriction":1,
"altTeaser":false,
"resultingUnit":"Regular"
}
]
},
{
"id":487,
"name":"NBA",
"events":[
{
"id":1120192519,
"starts":"2020-05-01T17:00:00Z",
"home":"Test Team B",
"away":"Test Team A",
"rotNum":"123",
"liveStatus":0,
"status":"O",
"parlayRestriction":0,
"altTeaser":false,
"resultingUnit":"Regular"
}
]
}
]
}
For example finding the league name "Germany - Bundesliga" I solved it by doing
// retrieve league by searching in the fixture collection
func FindLeagueFixture(name string) (pinnacle.Fixtures, pinnacle.League, error) {
var fixtures []pinnacle.Fixtures
err := db.C(FIXTURES).Find(
bson.M{"league.name": bson.RegEx{
Pattern: name,
Options: "i",
}}).All(&fixtures)
if err != nil {
return pinnacle.Fixtures{}, pinnacle.League{}, err
}
But now I have to event home/away names within league events. For example, finding "SC Rasta Vechta". What's the best way to handle this?
I've tried something like (No regex usage yet, since I'm having trouble already. Only trying count, not doing the whole unmarshaling for now)
// retrieve sport team by searching in the fixture collection
func FindHomeOrAwayFixture(name string) (pinnacle.Fixtures, pinnacle.League, error) {
var fixtures []pinnacle.Fixtures
// find home
c, err := db.C(FIXTURES).Find(
bson.M{"league": bson.M{"$elemMatch": bson.M{"home": name}}}).Count()
if err != nil {
return pinnacle.Fixtures{}, pinnacle.League{}, err
}
fmt.Println(c)
}

Add subcollection in cloud firestore using swift

I have a simple problem. I have an existing document in cloud firestore and I simply want to add a subcollection to this document and add a document to this subcollection.
The following is my code for what I believe should do the job, but unfortunately doesn't. Also I dont get any errors.
var ref: DocumentReference? = nil
ref = db.collection("users").document("John").collection("newSubcollection").addDocument(data: [
"age": 25
]) { error in
if let err = err {
print("Error adding subcollection: \(err)")
} else {
print("subcollection added with ID: \(ref!.documentID)")
self.dismiss(animated: true, completion: nil)
}
}
The message I get is that it succesfully created the subcollection, but I dont see it. What is going wrong?

Firestore how to store reference to document / how to retrieve it?

I am new to Firestore/Firebase and I am trying to create a new document with one of the fields being a document reference to an other document. I have read all the guides and examples from Firebase and did not find anything...
Also, when I retrieve this document I created, I would be able to access what is inside the reference I added inside. I have no idea how to do that.
Here is some code I tried for the creating part
let db = Firestore.firestore()
// Is this how you create a reference ??
let userRef = db.collection("users").document(documentId)
db.collection("publications").document().setData([
"author": userRef,
"content": self.uploadedImagesURLs
]) { err in
if let err = err {
print("Error writing document: \(err)")
} else {
print("Document successfully written!")
}
}
You're just missing one step. This took me a while to figure out as well.
First, store a variable DocumentReference!
var userRef: DocumentReference!
Then, you want to create a pointer to the document ID — create a DocumentReference from that <- this part you are missing
if let documentRefString = db.collection("users").document(documentId) {
self.userRef = db.document("users/\(documentRefString)")
}
Finally, resume saving your data to the database
db.collection("publications").document().setData([
"author": userRef,
"content": self.uploadedImagesURLs
]) { err in
if let err = err {
print("Error writing document: \(err)")
} else {
print("Document successfully written!")
}
}
Hope that helps!
This way works perfectly for me:
let db = Firestore.firestore()
let documentRefString = db.collection("users").document(documentID)
let userRef = db.document(documentRefString.path)
Then, when you will set the data:
db.collection("publications").document().setData([
"author": userRef,
"content": self.uploadedImagesURLs
]) { err in
if let err = err {
print("Error writing document: \(err)")
} else {
print("Document successfully written!")
}
}

Setting Google FireStore Permissions to avoid overwriting data

I have a project I am working on that takes data written by the following statement in swift 4:
#IBAction func saveButton(_ sender: Any) {
db.collection("violets").document(plantName.text!).setData([
"Plant Name": "\(plantName.text ?? "")",
"Hybridizer": "\(hybridizer.text ?? "")",
"Registration Number": Int("\(registrationNumber.text ?? "")"),
"Type": "\(type.text ?? "")",
"Description": "\(generalDescription.text ?? "")",
"Notes": "\(notes.text ?? "")"
]) { err in
if let err = err {
print("Error writing document: \(err)")
} else {
print("Document successfully written!")
}
}
uploadImage(violetImage.image!)
}
This is written to my FireStore successfully:
My problem is when adding more data, its easy to overwrite an existing document in FireStore. I think the best way to go about fixing this is to implement specific permissions to restrict overwriting data.
My hope was to try to only allow overwrite if a user is Authenticated and if the document name wasn't already present in the database.
This is my FireStore permission config:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read : if request.auth.uid != null;
//allow write: if request.auth.uid != null && !data.exists
}
match /violets/{violetID} {
allow write: if !exists(violetID)
}
}
}
At this point is just denying all writing period. Am i misunderstanding the file structure of FireStore or is something else here wrong?
EDIT: Think I got closer but still no cigar...
So I was never actually able to get the permission validation itself to work; but I found a way to do it in code by validating that the document I was trying to write existed or not. Here was my final solution:
#IBAction func saveButton(_ sender: Any) {
let docRef = db.collection("violets").document(plantName.text!)
docRef.getDocument { (document, err) in
guard
let document = document,
let user = document.exists ? document : nil
else {
print("Plant does not exist in DB. Writting new Entry")
self.db.collection("violets").document(self.plantName.text!).setData([
"PlantName": "\(self.plantName.text ?? "")",
"Hybridizer": "\(self.hybridizer.text ?? "")",
"Registration Number": Int("\(self.registrationNumber.text ?? "")"),
"Type": "\(self.type.text ?? "")",
"Description": "\(self.generalDescription.text ?? "")",
"Notes": "\(self.notes.text ?? "")"
]) { err in
if let err = err {
print("Error writing document: \(err)")
} else {
print("Document successfully written!")
}
}
self.violetImage.image = self.violetImage.image?.resizeWithWidth(width: 120)
self.uploadImage(self.violetImage.image!)
self.itemFinishedAdding()
return
}
print("\(self.plantName.text!) is already in the database")
}
}
While this logic works... I am not quite satisfied with it. Still Chuggin' at it.