I'd like to update (or synchronize) the latest entry from a tree in my Firebase-Database.
The structure looks like this:
I want to observe the latest entry only, without fetching all entries as 'EventTypeChildAdded' does.
However, I really want to observe the latest entry, so I'd like to call a function whenever there is a new 'latest' entry, so when a child gets added.
I already found this piece of code.
(DatabaseRef).queryOrderedByKey().queryLimitedToLast(1).observeSingleEventOfType
But this does not seem to observe the latest entry.
I guess you are on the wrong way. childadded does exactly what you need. Check the doc again.
https://firebase.google.com/docs/database/admin/retrieve-data#child-added
For the first time childadded fetches all the list but then only the item just added to the list.
Child Added
The child_added event is typically used when retrieving a list of
items from the database. Unlike value which returns the entire
contents of the location, child_added is triggered once for each
existing child and then again every time a new child is added to the
specified path. The event callback is passed a snapshot containing the
new child's data. For ordering purposes, it is also passed a second
argument containing the key of the previous child.
EDIT:
To limit the childadded query to the last item:
ref.queryLimited(toLast: 1).observe(.childAdded) { (snapshot) in
// parse snapshot to get the last item
Related
I am just stucked at this since last few hours and I have tried everything that is possible to update these values in firebase.
I want to update
is_read_p: "0"
to
is_read_p: "1"
for every record in the database.
So far, I have tried this code,
[[[[_mainRef child:#"messages"] child:[NSString stringWithFormat:#"359_361"]]childByAutoId] updateChildValues:#{#"is_read_c":#"0"}];
But, instead of updating, it adds three more child like this:
I know there must be a silly mistake or I might be missing something. Please help me finding that missing part. Thanks. :)
Each time you call childByAutoId, the client creates a reference to a new unique child node. Since you then call updateChildValues on that new location, you're creating a new child node, instead of updating an existing one.
Firebase doesn't support update queries. You'll need to execute the query, process each matching node, and update them individually.
Also see:
Swift Firebase: Update specific objects resulting from Firebase query
Regarding Firebase documentation if you limit your query with "toLast" then when a child is added, if you already exceed the value (in my case f.e. 50) then child removed is also triggered because the first child is deleted from the scope.
The following listeners are the ones I have on the code:
firebaseReference.queryOrderedByKey().queryLimited(toLast: 50).observe(.childAdded...
firebaseReference.queryOrderedByKey().queryLimited(toLast: 50).observe(.childRemoved...
I would like to know if there is some way to differenciate when a child is really deleted or a child is just deleted from the scope.
Thank you so much,
any further information don't hestiate to ask.
Firebase does not send along information on why you're receiving the .childRemoved event, so there's no way to know it based on that.
The only thing I can quickly think of is adding a .value listener for each child, which will then fire with null when the child gets deleted.
You'll want to remove the .value listener after you receive the .childRemoved handler, to not have dangling listeners for each child you've ever seen, so this may become more work than it's worth.
When I call this observe function from in my viewcontroller, the .childadded immediately returns a object that was already stored instead of has just bin added like .childadded would suspect.
func observe(callback: RiderVC){
let ref = DBProvider.Instance.dbRef.child("rideRequests")
ref.observe(DataEventType.childAdded) { (snapshot: DataSnapshot) in
if let data = snapshot.value as? NSDictionary {
let drive = cabRide(ritID: ritID, bestemming: bestemming,
vanafLocatie: vanaf, taxiID: taxiID, status: status)
print(drive)
callback.alertForARide(title: "Wilt u deze rit krijgen?", message: "Van: \(vanaf), Naar: \(bestemming)", ritID: ritID)
}
}
}
When I try this function with .childchanged, I only get a alert when it is changed like it suppose to do, but when doing .chiladded, it just gets all the requests out of the database and those requests were already there.
When I add a new request, it also gives an alert. So it works, but how can I get rid of the not added and already there requests?
Does anybody know this flaw?
This is working exactly as promised. From the documentation:
Retrieve lists of items or listen for additions to a list of items.
This event is triggered once for each existing child and then again
every time a new child is added to the specified path. The listener is
passed a snapshot containing the new child's data.
That might seem weird at first, but this is generally what most developers want, as it's basically a way of asking for all data from a particular branch in the database, even if new items get added to it in the future.
If you want it to work the way you're describing, where you're only getting new items in the database after your app has started up, you'll need to do a little bit of work yourself. First, you'll want to add timestamps to the objects you're adding to the database. Then you'll want to do some kind of call where you're asking to query your database by those timestamps. It'll probably look something like this:
myDatabaseRef.queryOrdered(byChild: "myTimestamp").queryStarting(atValue: <currentTimestamp>)
Good luck!
The way I set up my database structure was like this:
It starts with Lists then there is a child that shows the users UID then inside that there is one item.
The one item inside the UID gets updated every time I attempt to save new data. Instead of adding another item the same one just keeps changing. I was wondering how I could instead of update the same one item every time add more items.
The way that I save my data is with this line of code.
let user = FIRAuth.auth()?.currentUser
let item: String = self.ItemTextField.text!
self.ref.child("Lists").child(user!.uid).setValue(["Items": item])
More idiomatic is to store the list of items with so-called push ids:
Lists
twEymn...
-Km....: "Yoghurt"
You'd do this with:
self.ref.child("Lists").child(user!.uid).childByAutoId().setValue(item)
The childByAutoId() generates a unique, sequential ID. It's similar to an array index, but this one works reliably in multi-user environments and when users can be offline. Read this blog post about these so-called push ids.
Alternatively you can use the name of the item as the key (if the item has to be unique in the list):
Lists
twEymn...
"Yoghurt": true
In that case the code becomes:
self.ref.child("Lists").child(user!.uid).child(item).setValue(true)
One thing you'll note is that both of these approaches only deal with the newly added item, instead of the list of items as a whole. This is a general pattern you'll see when using Firebase. By isolating your modifications, your app will be more scalable without users getting into each other's way.
The problem is that you are setting a key-value pair ("Items" : item) so that each time it is updating the value for the same key. What you could do instead is ("Items" : [your array of items here]), which will update a list of items for the same key each time.
You could also fetch the current list of items, append your new item locally, and then update.
I have an iOS app that synchronises to Parse.com.
It can find anything that was added to Parse and add it to Core Data using PFQuery. It can also check for any data that has been updated and update accordingly.
However, I'm not sure how to find objects that have been deleted on Parse.com.
Does anyone know of a query that will list the ObjectIDs that have been deleted and the date of their deletion? I can then remove them from the Core Data on the app.
I needed this function, too, but figured that marking rows as deleted will bloat the data and add a condition to every query. So I created a Deletion class. It records only the class name and ID of any deleted row, so it stays pretty small:
function recordDeletion(klass, identifier) {
var Deletion = Parse.Object.extend("Deletion");
var deletion = new Deletion();
deletion.set("klass", klass);
deletion.set("identifier", identifier);
return deletion.save();
}
// for every class that you want deletions recorded, add one of these...
Parse.Cloud.beforeDelete("MyClass", function(request, response) {
recordDeletion("MyClass", request.object.id).then(function() {response.success();});
});
My iOS clients record the date when they last fetched data, then get everything newly created/updated from MyClass (+ others) and Deletion. With that, the can delete the Deletions locally.
Over a longer period, the clients remove all of the locally cached data and get a fresh copy of everything (except Deletions). This allows me to have a scheduled job on the server that will empty the Deletion table (on a cycle that's much longer than the client's cycle).
There is no provided API for this.
As per the comment from #Fogmeister you can tag objects as deleted and update like that. Alternatively you can maintain a specific list of deleted ids (potentially using Parse.Cloud.beforeDelete) and then make a specific request to get only the deletions.
In either case you will need to explicitly manage the scheme you choose and also decide how and when to clean up the deleted objects / deletion records.