Why doesn't add event be triggered when Collection fetch successfully? - javascript

var documents = new Backbone.Collection();
documents.url = "/documents";
documents.bind("add", function(doc){
console.log(doc);
});
documents.fetch();
Why doesn't the add event triggered when the fetch function gets the array of models successfully?

What documentation says:
When the model data returns from the server, the collection will reset ...
If you'd like to add the incoming models to the current collection, instead of replacing the collection's contents, pass {add: true} as an option to fetch.
So the answer to your question: call fetch like this
documents.fetch({add: true});
And it will work fine.

I think the event add is fired after you add elements to an already populated Collection.
In this specific case you can listen to the reset event instead of add. Also remember to verify that your collection it's getting data at all.

Related

Delete a full document

I'm trying to delete a full document in a collection.
I have a collection called "pushes", every document inside gets an auto generate id from firebase.
I use this code to listen to create event of pushes:
functions.firestore.document('pushes/{msgId}').onCreate(ev => {
});
Everything works well I send my push but I want to delete this request.
I tried this code:
admin.firestore().doc('pushes/'+querySnapshot.id)).delete();
Still doesn't work, I tried also to use the "where" query but I don't know the auto document id key to compare:
admin.firestore().collection('pushes').where('<WHAT HERE?????>', '==', id).get().delete()

How to only get new data without existing data from a Firebase?

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.

Meteor event for subscriber of collection for new insert of document in mongodb

I have a question regarding when a new document is added to mongodb
I have an order object that can be added server side after a meteor method call.
I have an admin page called ‘incomingOrders' subscribing to all orders.
What i would like to do , is just play a sound when on this page , when a new order is inserted into the database.
my client side collection updates with the new order, but i need it to show some sort of alert (i.e. alert box, sound , flashing screen!!!)
How would i exactly do this?
is there an event that can that is triggerd when a new document is inserted that i can subscribe to?
I have no code tested as i don’t have any idea how to do it.
So i found the answer to my question
I used the cursor.observe function to observer when a document is added to my collection.
Template['incomingOrders'].helpers({
orders:function(){
var cursor = Orders.find({},{sort: {createdAt: -1}});
// watch the cursor for changes
var handle = cursor.observe({
added:function(order){
if(!initializing){
console.log('order from handle');
console.log(order);
document.getElementById('xyz').play();
}
}
});
return cursor;
}
});
I have an initialising check (which is set to false in the rendered function of the template) as this function seems to be called on every element while the template is rendering . And then i simply call play on an audio element to alert me of a new document being added.
If there is a better way , please inform me!

Backbone.js I want to do model.fetch and have the data reflected back in the source collection

I'm really looking to understand the concept here (as opposed to receiving a code solution).
I have a collection that was populated by a fetch. I want to take a single model from the collection, fetch the latest data from the server, then have the data that came from the server put back into the collection's version of the model.
Restating with terms from Backbones docs: I'd like to ensure that I have the latest server state. I won't care about "change" events that are triggered because I'm expecting the model to change almost every time. Fetch resets the model's state from the server, so I should just be able to do something like this, right?:
[pseudo]
model.fetch();
in the fetch success handler call one of these:
this: collection.add(model, {merge: true});
..or: collection.set(model);
If that's not enough to accomplish my task, what concept am I missing?
EDIT - adding details
I call fetch():
controller.model.fetch({
success: function(model){
console.log(model);
updateView();
},
error: function(){
console.error('error fetching contact model');
}
});
The success callback is fired after the fetch(). I can see that the model has new data and that the Image has been modified and needs to be re-downloaded:
When I call my function that updates the view, nothing changes visibly because the latest data is still in the "changed" member...it seems. What's the standard way to get the latest data from "changed" into the "attributes" member? And is this made clear in the documentation?
There is no "collection's version of the model"
If you refer to a model in the collection and call fetch, there's nothing else needs to be done.
This model is already a part of the collection and the new data will populate.
Objects in javascript are passed by reference, so unless you clone it seeing something like model.clone(), you are referring to the same object.

BackboneJS: Load more items into a collection

In Backbone JS when I fetch a collection should I be fetching the entire collection or a small portion of it?
For example I have news feed collection in mongoDB that could have potentially 1000s of items. When the user hits the page I only want to show them the latest 10 items with the option to 'Load More'. But if they visit a specific item via URL http://site.com/#/feed/:itemID I want to be able to pull up that item's record.
1. How many document should I be fetching initially?
2. How would I got about fetching any item by id?
I ended up using the {add: true} statement when calling fetch on my collection. This prevents the collection from being replaced by the result of the fetch and but instead appends the result to the collection. I then also passed the 'skip' amount using the {data: {skip: amountOfItemsInCollectionAlready }, this is used on the server-side to get the correct batch of items from the database.
My final fetch method looks like this:
loadMore: function(e){
this.collection.fetch({
add: true,// this adds to collection instead of replacing
data:{// this is optional params to be sent with request
skip: this.collection.length// skip the number of items already in the collection
}
});
}
You probably don't want to just use Collection.fetch(), because you won't get the benefit of client-side caching - it'll drop the items you've already loaded from the server and reset the collection. You will probably need to extend Backbone.Collection with a custom function to retrieve more items. I used the following code in a recent project:
Backbone.Collection.extend({
// fetch list without overwriting existing objects (copied from fetch())
fetchNew: function(options) {
options = options || {};
var collection = this,
success = options.success;
options.success = function(resp, status, xhr) {
_(collection.parse(resp, xhr)).each(function(item) {
if (!collection.get(item.id)) {
collection.add(item, {silent:true});
}
});
if (!options.silent) collection.trigger('reset', collection, options);
if (success) success(collection, resp);
};
return (this.sync || Backbone.sync).call(this, 'read', this, options);
}
});
This is mostly copied from the default fetch() code, but instead of dropping existing items it will add new ones. You'd probably want to implement something server-side, using the options object as Julien suggests to pass in the parameters of what items you want to load, probably either a page number (if you want to control page size on the server) or a start-stop pair (if you want to control it on the client).
1 - You should be fetching 10
Add a page argument to your collection and have the backend code return the page matching (10/page). /my_objects?page=2 to get records 10-20 etc.
You do this like this (untested):
collection.fetch({data: {page:2}})
Or you alter the URL directly
2 - To fetch an item by ID you create the model
object = new Model({id: 1})
and fetch it
object.fetch()

Categories

Resources