I have a block of data holding user information, so the tree of data looks something like:
app
-Jweljralsdjfo49
username: "Fred"
age: 25
shoesize: 16
I'm trying to do:
var ref = new Firebase(my_app_path + stored_user_id);
ref.remove();
I've also tried;
var ref = new Firebase(my_app_path);
var child = ref.child(stored_user_id);
child.remove();
Neither one works, in that the data is always still there.
The documentation for remove() states: "Remove the data at this Firebase location. Any data at child locations will also be deleted.", so I expect it to all to be gone.
I've tried adding a callback, and in each case the callback gets called with null (indicating success, quoting the docs: "The callback will be passed an Error object on failure, else null.").
What am I doing wrong? Is it because I'm using the user ID? I'm not using any security rules at the moment, but once I do, for security restrictions, I don't want non-users to be able to delete user content.
THANKS!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EDIT: Found the problem.
I'm using EmberFire, which works fine; but the EmberFire.Object which keeps track of the object has to be destroy()'d, and then I had to do:
Ember.run.later(function() {
var ref = new Firebase(my_app_path + stored_user_id);
ref.remove();
}, 1);
In order for the object to be officially gone, and for Ember/EmberFire to release its grip on the data.
you can probe adding $ to remove.
Example:
var ref = new Firebase(my_app_path + stored_user_id);
ref.$remove();
work for me.
Related
Problem
In a social media app I am making with react native and firebase, I am trying to grab the number of comments a post has using the snapshot function of a variable I have saved on my servers, then I am going to add one to this variable when a user adds a new comment. My code to do so is right here:
firebase.database().ref('posts').child(this.state.passKey).update({
comments: firebase.database().ref('posts/'+this.state.passKey).child('comments').snapshot.val() + 1
})
When I actually run this code, I get an error saying:
Reference.child failed: First argument was an invalid path = "undefined".
Paths must be non-empty strings and can't contain ".","#","$","[", or "["
At first I thought this might be that the "this.state.passKey" wasn't actually passing the key, but putting in a key I copied from the server didn't fix the problem.
My Server
-
To get the comments of particular post you should do like this
let postId='someId'
postRef=`/posts/${postId}`
firebase.database().ref(postRef).once("value", dataSnapshot => {
comment=dataSnapshot.val().comments
});
It looks like you're expecting this bit of code to query the database:
firebase.database().ref('posts/'+this.state.passKey).child('comments').snapshot.val() + 1
Unfortunately, it doesn't work that way. There's no snapshot property on a database Reference object returned by child() or ref().
Instead, you'll need to query the database at that reference, then when you're called back with its value, you can apply it elsewhere.
var ref = firebase.database().ref('posts/'+this.state.passKey+'/comments')
ref.once('value', function(snapshot) {
// use the snapshot here
})
I have a users table on Firebase and each user has an email prop.
Structure looks like:
Users -> User UID (looks like n8haBbjgablobA2ranfuabu3aaaga2af) -> User Obj which includes email prop.
I'd like to get an array of all the users' emails (~1m).
How can I most efficiently do this?
Ps.:
I tried:
usersRef.startAt(0).endAt(20).once("value", function(snapshot) {
console.log('FIRST 20');
console.log(snapshot.val()); // null
});
But that fails.
Probably the most efficient approach in terms of data reads would be to denormalize your data. You could store the email addresses both in the individual user nodes and in an emailAddresses node. Then you could just query the emailAddresses node directly for your list of emails.
Still ~1m email address nodes would probably be too much all at once. I'd probably grab it in chunks... I'm guessing.
Update
"Grabbing in chunks" is essentially pagination. I would try to use something off the shelf before trying to roll my own pagination solution.
Pagination libraries to check out:
Firebase Utils Pagination: This is developed by Firebase, but they say it is experimental and not ready for production use. But, it's probably still worth messing around with.
firebase-paginator: this is developed by a community member and it seems pretty solid.
If you want to roll your own pagination, check out:
#kato's response in this StackOverflow answer He makes an interesting point about the potential problem with paginating a real time data set, but then provides some good starter code
Here's a good blog entry that talks about the code that I think is a part of the firebase-paginator library I linked to above
Everybody in their answers said that it was an easy thing, yet had no working solutions. Here's what I came up with:
usersRef.orderByChild('uid').limitToFirst(100).once('value', function (snapshot) {
var users = snapshot.val()
var uids = Object.keys(users);
var lastUid = uids[uids.length - 1];
// could be another property than uid, for example email, or username. Ps.: Consider that the last ID from the previous chunk will be duplicated.
usersRef.orderByChild('uid').startAt(lastUid).limitToFirst(100).once('value', function (snapshot) {
var users = snapshot.val()
var uids = Object.keys(users);
console.log(uids);
var lastUid = uids[uids.length - 1];
// re-run function until done
})
})
Since this is a one-time deal, an option is to simply iterate over each node in the parent 'data' node capturing the child data, stripping out the email address and dumping that to a file.
the event you want is
child_added: 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.
and the code to iterate all of the child nodes in the data node is
var dataRef = firebase.database().ref('myRootRef/data');
datRef.on('child_added', function(data) {
//data.val() will contain the child data, such as the email address
//append it to a text file here (for example), save to disk etc.
});
The key here is that this event is triggered once for each child, similar to iterating over all of the indexes in an array.
This will retrieve each child and present it to your app, one child at a time, iterating over all the children within the node.
It's going to take a while with that many nodes to chew through.
I have a node in Firebase getting continually updated with information from a logfile. The node is lines/ and each child of lines/ is from a post() so it has a unique ID.
When a client first loads, I want to be able to grab the last X number of entries. I expect I'll do this with once(). From then on, however, I want to use an on() with child_added so that I get all new data. However, child_added gets all data stored in the Firebase and, after the initial setup, only want the new stuff.
I see that I can add a limitToLast() on the on(), but, if I say limitToLast(1) and a flood of entries come in, will my app still get all the new entries? Is there some other way to do this?
You need to include a timestamp property and run a query.
// Get the current timestamp
var now = new Date().getTime();
// Create a query that orders by the timestamp
var query = ref.orderByChild('timestamp').startAt(now);
// Listen for the new children added from that point in time
query.on('child_added', function (snap) {
console.log(snap.val()
});
// When you add this new item it will fire off the query above
ref.push({
title: "hello",
timestamp: Firebase.ServerValue.TIMESTAMP
});
The Firebase SDK has methods for ordering, orderByChild() and methods for creating a range startAt(). When you combine the two you can limit what comes back from Firebase.
I think there is a problem in #David East's solution. He is using the local timestamp which may cause problem if the time is not accurate in client device. Here is my suggested solution (iOS Swift):
Using observeSingleEvent to get the complete data set
Then returned it in reversed order by reversed()
Get the last timestamp by for example data[0].timestamp
Using queryStarting for timestamp
self._dbref.queryOrdered(byChild: "timestamp").queryStarting(atValue: timestamp+1)
.observe(.childAdded, with: {
snapshot in
print(snapshot.value)
})
You have the right idea. child_added should be called only for the new nodes. Without source code it's hard to tell why you get all the data in your child_added event.
You can check the chat demo app to see how they load new chat messages. The use case sounds similar.
https://github.com/firebase/firechat/blob/master/src/js/firechat.js#L347
Here's temporary but quick solution:
// define a boolean
var bool = false;
// fetch the last child nodes from firebase database
ref.limitToLast(1).on("child_added", function(snap) {
if (bool) {
// all the existing child nodes are restricted to enter this area
doSomething(snap.val())
} else {
// set the boolean true to doSomething with newly added child nodes
bool = true;
}
});
Disadvantage: It will load all the child nodes.
Advantage: It will not process existing child nodes but just the newly added child nodes.
limitToLast(1) will do the work.
I want to filter data from firebase, Im using firebase-util scroll for scrolling,
I have the following code
var baseRef = new Firebase(urlToFirebaseData).orderByChild("name").equalTo("john_doe");
var scrollRef = new Firebase.util.Scroll(baseRef, '$priority');
// establish an event listener as you would for any Firebase ref
scrollRef.on('child_added', function(record) {
console.log('added child', record);
});
this gives me an error
Error: First argument to Firebase.util.Scroll must be a valid Firebase ref. It cannot be a Query (e.g. you have called orderByChild()).require.18.r.Scroll
how can I query using firebase-util, I have tried putting the query in different places to no avail
The error message is pretty explicit:
First argument to Firebase.util.Scroll must be a valid Firebase ref. It cannot be a Query
The reason for this is that Firebase.util.scroll needs to build its own query to be able to implement scrolling on that location and Firebase only handles one query per location.
If you want to use Firebase.util.Scroll for the scrolling, you'll have to separate the data out into its own location so that you can do something like:
var baseRef = new Firebase(urlToFirebaseData).child("users_items").child("john_doe");
var scrollRef = new Firebase.util.Scroll(baseRef, '$priority');
I have a Player class. Players can have x number of Trophies. I have the Player objectId and need to get a list of all of their Trophies.
In the Parse.com data browser, the Player object has a column labeled:
trophies Relation<Trophy>
(view Relations)
This seems like it should be so simple but I'm having issues with it.
I have the ParseObject 'player' in memory:
var query = new Parse.Query("Trophy");
query.equalTo("trophies", player);
query.find({
/throws an error- find field has invalid type array.
I've also tried relational Queries:
var relation = new Parse.Relation(player, "trophies");
relation.query().find({
//also throws an error- something about a Substring being required.
This has to be a completely common task, but I can't figure out the proper way to do this.
Anyone know how to do this in Javscript CloudCode?
Many thanks!
EDIT--
I can do relational queries on the user fine:
var user = Parse.User.current();
var relation = user.relation("trophies");
relation.query().find({
I don't understand why this very same bit of code breaks if I'm using a non-user object.
I finally sorted this out, though there is a caveat that makes this work differently than the documentation would indicate.
//Assuming we have 'player', an object of Class 'Player'.
var r = player.relation("trophies");
r.query().find({
success: function(trophies){
response.success(trophies); //list of trophies pointed to by that player's "trophies" column.
},
error: function(error){
response.error(error);
}
})
The caveat: You must have a 'full' player object in memory for this to work. You can't save a player object, grab the object from the success callback and have this work. Some reason, the object that is returned in the success handler is appears to be an incomplete Parse.Object, and is missing some of the methods required to do this.
Another stumbling block about the Parse.com Javascript SDK- A query that finds nothing is still considered successful. So every time you query for something, you must check the length of the response for greater than 0, because the successful query could have returned nothing.
This is what worked for me:
var Comment = Parse.Object.extend("Comment");
var commentsQuery = new Parse.Query(Comment);
commentsQuery.equalTo("parent", video);//for the given 'video' instance, find its children (comments)
commentsQuery.descending("createdAt");
return commentsQuery.find();
Note: of course, video is an instance of the Video class. And returning find() means I'll have to handle the 'promise' in whatever function calls this one.
And here is another function coming from the other angle:
getRecentCommentsOfAllVideos: function(limit) {
var Comment = Parse.Object.extend("Comment");
var commentsQuery = new Parse.Query(Comment);
commentsQuery.descending("createdAt");
commentsQuery.limit(limit);
commentsQuery.include("parent");//this enables the details of the comment's associated video to be available in the result
return commentsQuery.find();
}
(Be sure to read https://parse.com/docs/js_guide and search for the line that says "Include the post data with each comment".)
I also looked at these materials; maybe they'll help you (though they weren't much help for me):
https://parse.com/questions/how-to-retrieve-parent-objects-with-their-children-in-one-call-javascript-api
http://blog.parse.com/2011/12/06/queries-for-relational-data/