How to insert unique ID into Firebase item on initial push()? - firebase

When using push() with Firebase, Firebase generates a unique ID, such as -JZl_BbXymAnOCPppMzN. I'm trying to figure out if there's any way to get that ID into the item I'm pushing during that first push(). For example, say I'm pushing an item as such:
var uid = "notset";
uid = fb.push({Name: name, Status: status, Position: position, UID: uid});
In this example, uid.name() holds my unique ID. So my first thought was to then update the item with the unique ID I now know, like:
var uidname = uid.name();
fb.child(uid.name()).update({UID: uidname});
And this does work.
However, I'm also relying on an on() to detect children added so I can deal with them as they arrive. For example:
fb.on('child_added',function(dataSnapshot) {
var newstatus = dataSnapshot.val();
var status = newstatus.Status;
var name = newstatus.Name;
var position = newstatus.Position;
var uid = newstatus.UID;
console.log
("Name: "+name+", Status: "+status+", Position: "+position+", UID: "+uid);
});
But because of the async nature of Firebase, this on() runs after the push() but before the update(). So my console.log() prints out a uid of notset instead of the correct UID.
Is there a different strategy I should be following? I suppose I can generate my own UIDs and push them to Firebase using firebaseRef.child('myUID').set(), but it seems there must be an easier way?

Firebase's push is a client-side operation, so nothing is sent to the server yet.
Instead of calling push with the data in one go, you can you split it into two separate calls:
var ref = fb.push();
/* use ref.name() here*/
ref.set({Name: name, Status: status, Position: position, UID: uid});

Not sure of this will work, but try this:
In fb.push, do not set the UID at all, leave it blank and firebase will generate it.
In fb.on, instead of newstatus.UID use dataSnapshot.name()

Related

Flutter Firebase firestore append data with unique ID

I'm working on the Flutter app where users can save multiple addresses. Previously I used a real-time database and it was easier for me to push data in any child with a unique Id but for some reason, I changed to Firestore and the same thing want to achieve with firestore. So, I generated UUID to create unique ID to append to user_address
This is how I want
and user_address looks like this
And this is how it's getting saved in firestore
So my question Is how I append data with unique id do I have to create a collection inside users field or the above is possible?
Below is my code I tried to set and update even user FieldValue.arrayUnion(userServiceAddress) but not getting the desired result
var uuid = Uuid();
var fireStoreUserRef =
await FirebaseFirestore.instance.collection('users').doc(id);
Map locationMap = {
'latitude': myPosition.latitude,
'longitude': myPosition.longitude,
};
var userServiceAddress = <String, dynamic>{
uuid.v4(): {
'complete_address': completedAddressController.text,
'floor_option': floorController.text,
'how_to_reach': howtoreachController.text,
'location_type': locationTag,
'saved_date': DateTime.now().toString(),
'user_geo_location': locationMap,
'placeId': addressId
}
};
await fireStoreUserRef.update({'user_address': userServiceAddress});
If I use set and update then whole data is replaced with new value it's not appending, so creating a collection is the only solution here and If I create a collection then is there any issue I'll face?
You won't have any issues per se by storing addresses in a separate collection with a one-to-many relationship, but depending on your usage, you may see much higher read/write requests with this approach. This can make exceeding your budget far more likely.
Fortunately, Firestore allows updating fields in nested objects via dot notation. Try this:
var userServiceAddress = {
'complete_address': completedAddressController.text,
'floor_option': floorController.text,
'how_to_reach': howtoreachController.text,
'location_type': locationTag,
'saved_date': DateTime.now().toString(),
'user_geo_location': locationMap,
'placeId': addressId
};
await fireStoreUserRef.update({'user_address.${uuid.v4()}': userServiceAddress});

Firebase Cloud Function onWrite child value

I am using Firebase Cloud Function to send FCM upon Real-Time Database Triggered event. How can I get the value of a child ('uid') inside of {followerUid}?
exports.sendFollowerNotification = functions.database.ref('/followers/{followedUid}/{followerUid}').onWrite(event => {
const followerUid = event.params.followerUid;
const followedUid = event.params.followedUid;
I know exactly what you are looking for...
var uid = event.data.val();
var uid1 = String(uid);
add this uid1 to title or body
const payload = {
notification: {
title: paypes
body: uid1
}
};
I'm not sure I understand what you're trying to do but will take a stab.
If you are looking to access the data of uid inside the node that triggered the function:
var uid = event.data.child("uid").val;
Have a look at the documentation on handling event data.
Due to recent change in the API.
Following give the data value.
event.before.val();
or
event.after.val();
As onWrite(), which triggers when data is created, updated, or deleted in the Realtime Database.
So it gives both before and after value.

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.

How to bypass unique ID and reference child nodes

My firbase database looks like this:
app
users
-gn4t9u4ut304u9g4
email
uid
How do I reference email and uid? When I try this:
$rootScope.dashtype.child('users').orderByChild('uid').equalTo($rootScope.auth.uid).on('value', function(snapshot){
$rootScope.user = snapshot.val();
console.log($rootScope.user);
})
I get the correct object, but with the unique id as root:
Object {-JvaZVrWGvJis0AYocBa: Object}
And because this is a dynamic property, I don't know how to reference the child objects. I just want to be able to access the user fields like this: $rootScope.user.email etc.
Since you're requesting a value, you get a list of users as a result. It may only be one user, but it's still a list of one.
You will have to loop over the snapshot, to get to the child node:
$rootScope.dashtype.child('users').orderByChild('uid').equalTo($rootScope.auth.uid).on('value', function(snapshot){
snapshot.forEach(function(userSnapshot) {
$rootScope.user = userSnapshot.val();
console.log($rootScope.user);
});
});
Since there's only a single user in the list, the loop for execute just once.
You are mixing regular Firebase JavaScript with AngularFire here. This means that you will need to inform AngularJS that you updated the scope, so that it will rerender the view:
$rootScope.dashtype.child('users').orderByChild('uid').equalTo($rootScope.auth.uid).on('value', function(snapshot){
snapshot.forEach(function(userSnapshot) {
$timeout(function() {
$rootScope.user = userSnapshot.val();
console.log($rootScope.user);
});
});
});

how to discard initial data in a Firebase DB

I'm making a simple app that informs a client that other clients clicked a button. I'm storing the clicks in a Firebase (db) using:
db.push({msg:data});
All clients get notified of other user's clicks with an on, such as
db.on('child_added',function(snapshot) {
var msg = snapshot.val().msg;
});
However, when the page first loads I want to discard any existing data on the stack. My strategy is to call db.once() before I define the db.on('child_added',...) in order to get the initial number of children, and then use that to discard that number of calls to db.on('child_added',...).
Unfortunately, though, all of the calls to db.on('child_added',...) are happening before I'm able to get the initial count, so it fails.
How can I effectively and simply discard the initial data?
For larger data sets, Firebase now offers (as of 2.0) some query methods that can make this simpler.
If we add a timestamp field on each record, we can construct a query that only looks at new values. Consider this contrived data:
{
"messages": {
"$messageid": {
"sender": "kato",
"message": "hello world"
"created": 123456 // Firebase.ServerValue.TIMESTAMP
}
}
}
We could find messages only after "now" using something like this:
var ref = new Firebase('https://<your instance>.firebaseio.com/messages');
var queryRef = ref.orderBy('created').startAt(Firebase.ServerValue.TIMESTAMP);
queryRef.on('child_added', function(snap) {
console.log(snap.val());
});
If I understand your question correctly, it sounds like you only want data that has been added since the user visited the page. In Firebase, the behavior you describe is by design, as the data is always changing and there isn't a notion of "old" data vs "new" data.
However, if you only want to display data added after the page has loaded, try ignoring all events prior until the complete set of children has loaded at least once. For example:
var ignoreItems = true;
var ref = new Firebase('https://<your-Firebase>.firebaseio.com');
ref.on('child_added', function(snapshot) {
if (!ignoreItems) {
var msg = snapshot.val().msg;
// do something here
}
});
ref.once('value', function(snapshot) {
ignoreItems = false;
});
The alternative to this approach would be to write your new items with a priority as well, where the priority is Firebase.ServerValue.TIMESTAMP (the current server time), and then use a .startAt(...) query using the current timestamp. However, this is more complex than the approach described above.

Resources