How do I structure my Geofire posts in my firebase database - swift

I have noticed on all other posts that any node/key with children was saved in the database in quotes and mine are not.
mine
Locations{
indexOn: "g"
}
others/what I assume it should be
Locations{
".indexOn": "g"
}
I didn't think anything of it till I came up on a similar error as this with the ".indexOn". I tried adding ".indexOn" but i received the error that no key can have the symbol .(along with a few other characters that aren't allowed) so I put it in without the . like so:
Locations{
(specific id){
g: "345jh3i5jh"
l{
0: 37
1: -120
}
indexOn: "g"
user: "0987435098723098Gjhf90"
}
}
So It seems to work as the observeEventType is returning the correct result sometimes but it still also gives me the error that i need to put ".indexOn" in database. How do I do this?
Any help and explicit examples would be appreciated as there are probably more problems with everything than I addressed. Doing this in swift and thanks for the read!

You seem to be trying to add index definitions to your database. That is indeed a great way to ensure the server can order and filter the data before returning the results to your app.
Indexes are defined by adding them to your Firebase Database rules in the Firebase Console > Database > Rules. Don't try to add them to your actual database, since:
you won't be able to save them, since they have a . in their key, which is an illegal character in the database
adding them won't help, since the database server only searches for .indexOn definitions in the database rules
See the Firebase documentation on adding indexes for more.

Related

Invalid hashing in Firebase Cloud Storage Rules Playground

I am testing hashing in the rules playground:
This returns "CRexOpCRkV1UtjNvRZCVOczkUrNmGyHzhkGKJXiDswo=", the correct hash of the string "SECRET" :
let expected = hashing.sha256("SECRET");
But this returns "SECRETpath/to/the/file.mp4", the argument itself instead of its hash:
let expected = hashing.sha256("SECRET" + request.resource.name);
Is it a bug in the rules playground?
Can hashing functions be used on dynamic values or is it intentionally prevented?
The strange rules playground behavior has been mentioned here before, this time with Firestore security rules: Firestore rules hashing returns identity
Firebaser here!
There are a few issues at play here. I think the primary source of confusion is that the hashing.sha256 function returns a rules.Bytes type. It appears that the Rules Playground in the Firebase Console incorrectly shows a string value when debugging the bytes type, but that is unrelated to behavior in production. For example, this Rule will always deny:
allow write: if hashing.sha256("SECRET" + request.resource.name) ==
"SECRET" + request.resource.name;
To get the behavior you're looking for, you need to use one of the conversion functions for the rules.Bytes type. Based on your question, you'll probably want the toBase64() function, but toHexString() is also an option. If you try these functions in your Rules, the Playground should start behaving correctly and the Rules will work as expected in production as well. So to put it all together, you'd write:
let expected = hashing.sha256("SECRET" + request.resource.name).toBase64();
For example, the rules listed below would allow you to upload a file called "foo/bar" (as Gqot1HkcleDFQ5770UsfmKDKQxt_-Jp4DRkTNmXL9m4= is the Base64 SHA-256 hash of "SECRETfoo/bar")
allow write: if hashing.sha256('SECRET' + request.resource.name).toBase64() ==
"Gqot1HkcleDFQ5770UsfmKDKQxt_-Jp4DRkTNmXL9m4=";
I hope this helps clear things up! Separately we will look into addressing the wrong debugging output in the Playground
After trying with emulators and the deployed app, it seems that hashing.sha256 does not work on dynamic data in any environment. The behavior is consistent, so I filed a feature request to add this function to storage security rules. This would be nice because it would allow passing signed data to the security rule for each file (for ex: an upload authorization obtained via a Cloud Function)
As of now, the workaround that I imagine is putting data in user custom token (or custom claims), so I can pass signed data to the security rule. It is not ideal because I need to re-sign with custom token for every file upload.

Trying to write a simple code in mongoldb, receiving an error

Just trying out MongoDB. So this might be a very basic issue. Trying to create a collection "info", but encountering errors as below. Appreciate the help.
uncaught exception: SyntaxError: missing : after property id :
#(shell):1:42
The code is as below :
db.info.insert({"userName":"John","mail”:"John#gmail.com","mobile":12345678},{"Transaction":[{"itemId":"a100","price":200},{"itemId":"a110","price":200}]},{"Payment":["Type":"Credi
t-card","Total":400,"Success":true]},{"Remarks":"1st complete record,payment successful"})
When you try, most of the developers would recommend to read the documentation of Insert data in mongodb. If you clearly understand, then you might understand the problem. The document was not well formatted which means you created object for each key:value pair. And payment is an array which holds objects. It was also not formatted.
You can try below code, and have fun with MongoDB
db.info.insert(
{
"userName":"John",
"mail":"John#gmail.com",
"mobile":12345678,
"Transaction":[{"itemId":"a100","price":200},{"itemId":"a110","price":200}],
"Payment":[{"Type":"Credit-card","Total":400,"Success":true}],
"Remarks":"1st complete record,payment successful"
}
)

How does resource.data.size() work in firestore rules (what is being counted)?

TLDR: What is request.resource.data.size() counting in the firestore rules when writing, say, some booleans and a nested Object to a document? Not sure what the docs mean by "entries in the map" (https://firebase.google.com/docs/reference/rules/rules.firestore.Resource#data, https://firebase.google.com/docs/reference/rules/rules.Map) and my assumptions appear to be wrong when testing in the rules simulator (similar problem with request.resource.data.keys().size()).
Longer version: Running into a problem in Firestore rules where not being able to update data as expected (despite similar tests working in the rules simulator). Have narrowed down the problem to point where can see that it is a rule checking for request.resource.data.size() equaling a certain number.
An example of the data being passed to the firestore update function looks like
Object {
"parentObj": Object {
"nestedObj": Object {
"key1": Timestamp {
"nanoseconds": 998000000,
"seconds": 1536498767,
},
},
},
"otherKey": true,
}
where the timestamp is generated via firebase.firestore.Timestamp.now().
This appears to work fine in the rules simulator, but not for the actual data when doing
let obj = {}
obj.otherKey = true
// since want to set object key name dynamically as nestedObj value,
// see https://stackoverflow.com/a/47296152/8236733
obj.parentObj = {} // needed for adding nested dynamic keys
obj.parentObj[nestedObj] = {
key1: fb.firestore.Timestamp.now()
}
firebase.firestore.collection('mycollection')
.doc('mydoc')
.update(obj)
Among some other rules, I use the rule request.resource.data.size() == 2 and this appears to be the rules that causes a permission denied error (since commenting out this rules get things working again). Would think that since the object is being passed with 2 (top-level) keys, then request.resource.data.size()=2, but this is apparently not the case (nor is it the number of keys total in the passed object) (similar problem with request.resource.data.keys().size()). So there's a long example to a short question. Would be very helpful if someone could clarify for me what is going wrong here.
From my last communications with firebase support around a month ago - there were issues with request.resource.data.size() and timestamp based security rules for queries.
I was also told that request.resource.data.size() is the size of the document AFTER a successful write. So if you're writing 2 additional keys to a document with 4 keys, that value you should be checking against is 6, not 2.
Having said all that - I am still having problems with request.resource.data.size() and any alternatives such as request.resource.size() which seems to be used in this documentation
https://firebase.google.com/docs/firestore/solutions/role-based-access
I also have some places in my security rules where it seems to work. I personally don't know why that is though.
Been struggling with that for a few hours and I see now that the doc on Firebase is clear: "the request.resource variable contains the future state of the document". So with ALL the fields, not only the ones being sent.
https://firebase.google.com/docs/firestore/security/rules-conditions#data_validation.
But there is actually another way to ONLY count the number of fields being sent with request.writeFields.size(). The property writeFields is a table with all the incoming fields.
Beware: writeFields is deprecated and may stop working anytime, but I have not found any replacement.
EDIT: writeFields apparently does not work in the simulator anymore...

Update string with firebase swift

I am trying to update a string with firebase swift but I am getting an error that I do not know how to get rid of.
I have this code part that is getting an error:
self.dbRef.child("feed-items/\(dataPathen)/likesForPost").updateChildValues("likesForPost": "7")
The error I am getting is expected "," seperator just before the :. I am using dbRef in another code part so I know i works and the dataPathen is being printed just before the above code part, so that is working too.
Can anyone help me with this bug?
Just change
self.dbRef.child("feed-items/\(dataPathen)/likesForPost").updateChildValues("likesForPost": "7")
To
self.dbRef.child("feed-items/\(dataPathen)/likesForPost").updateChildValues(["likesForPost": "7"])
And if you are only looking for incrementing a particular value at a specific node you might wanna check my answer's :- https://stackoverflow.com/a/39465788/6297658, https://stackoverflow.com/a/39471374/6297658
PS Prefer runTransactionBlock: to update properties like likeForPosts as there might be a moment when two users try to like same post at the same moment (Highly Unlikely, but still a possibility...),using updateChildValues might end up just updating like only from one user. But runTransactionBlock: keep firing until the changes of that thread have been committed to the node
updateChildValues accepts [AnyHashable:Any] dictionary:
self.dbRef.child("feed-items/\(dataPathen)/likesForPost")
.updateChildValues(["likesForPost": "7"])
Whenever updating values at any reference in Firebase Database, you need to pass a dictionary parameter for updateChildValues method as [AnyHashable: Any] for your path reference. So just update your code of line as below:
self.dbRef.child("feed-items/(dataPathen)/likesForPost").updateChildValues("likesForPost": "7")
Also if you need to update more than 1 key-value pairs then you can pass those key-value pairs inside dictionary by seperating using comma as below:
self.dbRef.child("feed-items/(dataPathen)/likesForPost").updateChildValues(["likesForPost": "7", "otherKey": "OtherKeyValue"])

mongodb looping collection + save, objects returned several times

I'm writing a pretty big migration and had this code (coffeescript):
db.users.find().forEach (user)->
try
#some code changing the user depending on the old state
db.users.save(user)
print "user_ok: #{user._id}"
catch error
print "user_error: #{user._id}, error was: #{error}"
Some errors occured. But they occured on already processed users:
user_ok: user_1234
#many logs
user_error: user_1234 ...
How come the loop takes already processed objects?
I ended up doing:
backup = { users: [] }
db.users.find().forEach (user)->
try
#some code changing the user depending on the old state
backup.users.push user
print "user_ok: #{user._id}"
catch error
print "user_error: #{user._id}, error was #{error}"
#loop backup and save
And it works nice now, but it seems really weird. What's the point behind all that please?
When you modify an object, it might be moved by the database. The database needs to take additional care to remember which objects have been visited already. This feature is called snapshotting, you can ask for a snapshotted query using
db.collection.find().snapshot()
However, even this doesn't make guarantees about objects that were inserted or deleted during the cursor iteration. A few more caveats are explained in the link to the documentation.
Another option is to perform an $orderby on an invariable unique index. Ideally, that index is also monotonic, so if you are using ObjectIds as primary keys then the _id field comes in pretty handy, like
db.collection.find().sort({"_id" :1});