Update user's collection sub-object with index auto increment - meteor

In a method, I need to write in the user's collection a new token on each call.
I need also to stock every token (no replacement or udpate of a single token).
I'm using sub-objects (like multi user's emails) : how can I auto increment dynamically the index, to write each new token 'after' the last written?
For example, if there is already 6 tokens written (so Auth.0.token to Auth.5.token), the new one will be automatically Auth.6.token.
Thanks
Below my working static code.
var authtoken = Random.id([20]);
Meteor.users.update({_id: Meteor.userId()}, {$set: {"Auth.1.token": authtoken}});

Just $push the token onto the end of the array instead of trying to set then value.
Meteor.users.update({_id: Meteor.userId()}, {$push: {Auth.token: authtoken}});

Related

Firestore rule to only add/remove one item of array

To optimize usage, I have a Firestore collection with only one document, consisting in a single field, which is an array of strings.
This is what the data looks like in the collection. Just one document with one field, which is an array:
On the client side, the app is simply retrieving the entire status document, picking one at random, and then sending the entire array back minus the one it picked
var all = await metaRef.doc("status").get();
List tokens=all['all'];
var r=new Random();
int numar=r.nextInt(tokens.length);
var ales=tokens[numar];
tokens.removeAt(numar);
metaRef.doc("status").set({"all":tokens});
Then it tries to do some stuff with the string, which may fail or succeed. If it succeeds, then no more writing to the database, but if it fails it fetches that array again, adds the string back and pushes it:
var all = await metaRef.doc("status").get();
List tokens=all['all'];
List<String> toate=(tokens.map((element) => element as String).toList());
toate.add(ales.toString());
metaRef.doc("status").set({"all":toate});
You can use the methods associated with the Set object.
Here is an example to check that only 1 item was removed:
allow update: if checkremoveonlyoneitem()
function checkremoveonlyoneitem() {
let set = resource.data.array.toSet();
let setafter = request.resource.data.array.toSet();
return set.size() == setafter.size() + 1
&& set.intersection(setafter).size() == 1;
}
Then you can check that only one item was added. And you should also add additional checks in case the array does not exist on your doc.
If you are not sure about how the app performs the task i.e., successfully or not, then I guess it is nice idea to implement this logic in the client code. You can just make a simple conditional block which deletes the field from the document if the operation succeeds, either due to offline condition or any other issue. You can find the following sample from the following document regarding how to do it. Like this, with just one write you can delete the field which the user picks without updating the whole document.
city_ref = db.collection(u'cities').document(u'BJ')
city_ref.update({
u'capital': firestore.DELETE_FIELD
})snippets.py

Firebase: Get the first result and update it

I would like to create into Firebase an "AccountQueues" object that will have account and names or the word "FREE" if it doesn't have account.
AccountQueues
-LEf-OrdKi65WG0NkQSG
AccountID:
"GR215"
Name:
"FREE"
When a user register I would like to take the first FREE AccountID and update it with the name of the user. Thank you for your help. I am developing an ionic 3 mobile app with this functionality.
You could use a query to check for an account that is free and limit it to the first search result. You want to use snapshotChanges() in order to return the key of the object.
returnedKey = null;
this.fireDB.list('AccountQueues', ref => ref.orderByChild('Name').equalTo('FREE').limitToFirst(1)).snapshotChanges().take(1).subscribe(res => {
res.map(doc => {
this.returnedKey = doc.key; //use this key to update object
});
});
Using the returned key from the query you can then update that object
this.fireDB.object(`AccountQueues/${this.returnedKey}`).update({Name:'Bob'});

change.after.val() returns full JSON object rather than value of the object

I'm working on a Firebase Cloud Function. When I log the value of change.after.val() I get a printout of a key-value pair
{ DCBPUTBPT5haNaMvMZRNEpOAWXf3: 'https://m.youtube.com/watch?v=t-7mQhSZRgM' }
rather than simply the value (the URL). Here's my code. What am I not understanding about .val() ? Shouldn't "updated" simply contain the URL?
exports.fanOutLink = functions.database.ref('/userLink').onWrite((change, context) => {
const updated = change.after.val();
console.log(updated);
return null
});
If you want only the URL value, you should include a wildcard in your trigger path for the URL key:
exports.fanOutLink = functions.database.ref('/userLink/{keyId}').onWrite((change, context) => {
console.log('keyId=', context.params.keyId);
const updated = change.after.val();
console.log(updated);
return null
});
In the Realtime Database, data is modeled as a JSON tree. The path specified in an event trigger identifies a node in the tree. The value of the node, being JSON, includes all child nodes. The change parameter for the trigger event refers to the value of the entire node.
I indicated above that you can change the trigger path to refer one level down. An alternative is to access the children of the node using the child() method of DataSnapshot.
Without knowing your use-case, it's hard to be more specific about the trigger event path you should use. Keep in mind that the event fires when any element of the node value changes, whether it be a simple value at the root level, or a value of a child node. It is often the case that you want the trigger to be as specific as possible, to better identify what changed. That's where wildcards in the path are useful. As I showed in the code I posted, the string value of a wildcard is available from the context parameter.

How to parse a collection's sub-object to find a unique result from many possibilities?

In my user's schema, I have a TokAuth Array with token sub-objects (like multiple mails addresses).
So in a method, when I search the tokens in the current user :
var id = Meteor.userId();
var usercurrent = Meteor.users.findOne({_id: id}, {fields: {"TokAuth": 1}});
var userToken = usercurrent.TokAuth.token;
I got in console.log(userToken)
[ 'fyAyXkXYrQdAlNpjuQfJ8RLU2TpfVGLnptlBs-m1h7xk',
I20170224-20:36:23.202(1)? 'YTwtUbhNTgiEfzFbJq7mESnOoOHeLYxWlqEeJJIG_GiV',
I20170224-20:36:23.206(1)? 'ViA4ydDITJtHDi2c_sArkNtpRYTjFqGL1ju2v00_-rFJ',
I20170224-20:36:23.206(1)? '51ImZcxRADLJr-FPCUL7EFGnTZYjHSZk3XxdqtBV2_fd',
I20170224-20:36:23.207(1)? 'S5aEvqjJ5zTUJqLFCPY1aZ1ZhsQppZTJtYKULM9aS2B3',
I20170224-20:36:23.207(1)? 'mhBs3oxHf2SxZfu2vCZhtiyPfg25fKMY8bKMZD8fx6IG',
I20170224-20:36:23.207(1)? '-rv0FiP-lxoqe8INyCJASV6rZpbgy3euEqB9sO9HsZSV',
I20170224-20:36:23.207(1)? 'zacr6_VBjHTsArov1LmQyZFLwI40fx4J7sygpLosTrli' ]
Beside, I've got a var who is equal to the last token in the userToken sub-object (that's of course expected : not to be the last one, but to be in the sub-object).
console.log (editAuth);
zacr6_VBjHTsArov1LmQyZFLwI40fx4J7sygpLosTrli
So how can I parse userToken to find a match with editAuth? If userToken was just a String, it will be simple but here...
Thanks
Is there a reason you are storing all the tokens as an array as opposed to just updating a single string each time?
That aside, you can check if an array contains a value by using the handy underscore function _.contains
Example:
_.contains( userToken, editAuth ); //returns true or false
In this case, you are simply trying to search for a string within an array of strings. #Sean already provided one solution.
If you are using the meteor ecmascript package then you can just simply use the native Array.includes method.
userToken.includes(editAuth);
On a side note, after using ECMAScript 2015+ for some time now, I find that I can use the native API for almost everything that I used to use underscore or lodash for. Check it out!

When utilizing the .push method can I write a copy of the id to the object?

I'm using the .push method on firebase to write new records. I'd like to save the key where the new record is saved to the record itself at the id key. Currently, I do this in 2 operations, first push the record and then update using the ref returned. Can I do this in 1 write? Does it not matter?
If you invoke the Firebase push() method without arguments it is a pure client-side operation.
var newRef = ref.push(); // this does *not* call the server
You can then add the key() of the new ref to your item:
var newItem = {
name: 'anauleau'
id: newRef.key()
};
And write the item to the new location:
newRef.set(newItem);
There's no method to do this in one operation. However, it typically does not matter, because you can always get the push id from the .key() method on the DataSnapshot.
But, there's nothing wrong either about storing the push id. So you coul create a function on the Firebase prototype.
Firebase.prototype.pushWithId = function pushWithid(data) {
var childRef = this.push();
data.key = childRef.key();
childRef.update(data); // or .set() depending on your case
return childRef;
};
var ref = new Firebase('<my-firebase-app>');
ref.pushWithId({ name: 'Alice' });
Take caution with modifying the prototype of functions you do not own. In this case, you'll likely be fine. This method does little, and there's not much of a chance that the Firebase SDK gains a .pushWithId() method.

Resources