I have a subscription:
Meteor.subscribe(
'FavCollection',
Session.get('current_query'),
Session.get("sortCollectionBy"),
{
onReady: function () {
console.log(FavCollection.find().fetch().length);
}
}
);
If i change my session variable sortCollectionBy, the subscription gets renewed. In my publish function I limit the results to an amount of 100 documents. So in my FavCollection there should always be a maximum of 100 docs. But it is not.
The onReady fires when the new documents are inserted. So directly in my onReady-callback I have a maximum amount of 200 components. The purging process starts after(!) the subscription callback. But I need to know the moment when the Collection is purged from the old documents (the moment when there are 100 docs again in my collection). Is there a callback like waitForPurge or something? Am I missing a point and my understanding of this is wrong? Should I cancel the subscription and make a new (and load overlapping documents twice)?
Related
I'm using Meteor Admin project stub (https://github.com/yogiben/meteor-admin).
I amended my data - posts collection in main.coffee to include some custom filtering defined in buildPostSearch function:
Router.map ->
//cut
#route "dashboard",
path: "/dashboard"
waitOn: ->
[
subs.subscribe 'posts'
]
data: ->
posts: Posts.find( buildPostSearch() ).fetch()
buildPostSearch = () ->
console.log "Executed."
{ //filter object constructed depending on Session parameters }
This works correctly, but it is being invoked multiple times on page refresh. I can see in browser console:
Executed.
Executed.
Executed.
Executed.
Executed.
Executed.
(...around 50 times)
I am worried about performance. Does it query DB so many times? Is there any better way to do it?
The data hook is reactive, so it's perfectly normal for it to fire multiple times.
It's important to remember that when it runs it's fetching documents from your local minimongo cache and not from the actual database. Each of those find operations is actually taking a minuscule amount of time, so performance is not a concern.
As for why it's running so many times, I suspect that may have to do with the nature of buildPostSearch. As you note in the comments, buildPostSearch depends on session variables so each time one of them changes, your data hook will execute again.
Additional note: I think you mean data: -> and not data -> in your sample code.
So I have an external process that periodically updates a collection in the Mongo database backing my Meteor app. I would like my Meteor app to take a particular action and update a different collection every time this first collection is updated. Is there a way I can listen to a collection in Meteor? Note, that I'm only concerned about the server side here.
You can use an observer:
CollectionOne.find({createdAt: {$gte: new Date()}}).observe({
added: function (document) {
// Do something to collection 2
},
changed: function (newDocument, oldDocument) {
// ...
},
removed: function (oldDocument) {
// ...
}
});
So added, changed and removed are fired when the documents from CollectionOne are added, changed or removed respectively.
You can use the callbacks of these to do something to a second Collection, or do other logic.
Also, note you can change the query. I've used createdAt to ensure that the observer only fires for new documents. (If they have a createdAt field with the date they were inserted).
The reason for this is the observe fires once initially for every document that matches the query.
Is there a way to know when data has been initially fully fetched from the server after running Deps.autorun for the first time?
For example:
Deps.autorun(function () {
var data = ItemsCollection.find().fetch();
console.log(data);
});
Initially my console log will show Object { items=[0] } as the data has not yet been fetched from the server. I can handle this first run.
However, the issue is that the function will be rerun whenever data is received which may not be when the full collection has been loaded. For example, I sometimes received Object { items=[12] } quickly followed by Object { items=[13] } (which isn't due to another client changing data).
So - is there a way to know when a full load has taken place for a certain dependent function and all collections within it?
You need to store the subscription handle somewhere and then use the ready method to determine whether the initial data load has been completed.
So if you subscribe to the collection using:
itemSub = Meteor.subscribe('itemcollections', blah blah...)
You can then surround your find and console.log statements with:
if (itemSub.ready()) { ... }
and they will only be executed once the initial dataset has been received.
Note that there are possible ocassions when the collection handle will return ready marginally before some of the items are received if the collection is large and you are dealing with significant latency, but the problem should be very minor. For more on why and how the ready () method actually works, see this.
Meteor.subscribe returns a handle with a reactive ready method, which is set to true when "an initial, complete snapshot of the record set has been sent" (see http://docs.meteor.com/#publish_ready)
Using this information you can design something simple such as :
var waitList=[Meteor.subscribe("firstSub"),Meteor.subscribe("secondSub"),...];
Deps.autorun(function(){
// http://underscorejs.org/#every
var waitListReady=_.every(waitList,function(handle){
return handle.ready();
});
if(waitListReady){
console.log("Every documents sent in publications is now available.");
}
});
Unless you're prototyping a toy project, this is not a solid design and you probably want to use iron-router (http://atmospherejs.com/package/iron-router) which provides great design patterns to address this kind of problems.
In particular, take a moment and have a look at these 3 videos from the main iron-router contributor :
https://www.eventedmind.com/feed/waiting-on-subscriptions
https://www.eventedmind.com/feed/the-reactive-waitlist-data-structure
https://www.eventedmind.com/feed/using-wait-waiton-and-ready-in-routes
I'm having trouble with realizing a reactive publication with a moving date. I have a calendar app with events/meetings. Im displaying these events on a special view page but i only want to display events of today and only with a starting time of currenttime - 30 mins.
The code im having and trying always works fine on initial load, after refreshing and when I add/delete an event from an admin page (collection gets refreshed?). But when I leave the page open the events which have passed just stay on the page. Whenever I add/remove a event via the admin page the publication is updated just fine. I assume this is because the publication isn't refreshing the date in the query or something?
I have tried:
normal publications and just subscribing via either iron-router
before hook or via Deps.autorun
publish all events and filtering on the client side
a publication with observeChanges
keep the vars in a deps.autorun function and passing them via the subscription as parameters
but I just keep getting the same results.
publication with observeChanges:
Meteor.publish('currentEventsObserve', function(calId) {
var self = this;
var nowMin30mins = moment().subtract('minutes',30).valueOf();
var endOfToday = moment(moment().format('DD-MM-YYYY 23:59'), 'DD-MM-YYYY HH:mm').valueOf();
var handle = Events.find({
calId : calId, //CalendarId
eventDate: { $gt: nowMin30mins, $lt: endOfToday }
},
{
sort: { eventDate: 1 },
limit: 5
}).observeChanges({
added: function(id,event){
//console.log("added: ",id,event);
self.added("events", id, event);
},
removed: function (id,event) {
//console.log("removed: ",id,event);
self.removed("events", id);
}
});
self.ready();
self.onStop(function () {
handle.stop();
});
});
As said before: the above works fine on initial load and refreshes, but after leaving the page open for a while the events are staying on there and not being removed from the publication.
Also, whenever I check the collection ones certain events already should have been removed via Events.find().fetch() for example, the events are still there, so it's not the template which isn't updating correctly.
I hope it's clear what I mean. I have read many other questions about this sort of reactivity but I just can't figure it out.
The problem is that nowMin30mins is only computed once when the publication is activated, and won't update afterwards, even though you have an observeChanges on Events. You basically have two constant values (nowMin30mins and endOfToday) bracketing the documents that will be shown and only adding or removing items will cause them to disappear.
I can think of two ways for how you'd want to do this reactively.
You can put all the reactivity on the client. Just send the entire day's events over in a publish, which is very simple, and have the client filter out what's between 30 mins from now and the end of the day using Date.now() in a computation that updates every minute or so, or when new events are added/deleted. It doesn't seem to incur a lot of overhead to store those events anyway and you can offload the computational cost of observes, which can build up if you have a lot of clients
If you want to do it on the server, you'll have to do things a little more carefully than what you have now. Because the live query won't account for the change in time, you'll need to watch all of today's events and then add or remove them from the subscription if they are created, or deleted or go out of range, respectively. To reiterate, you can't do this purely with an observeChanges because the current time is always changing.
I understand that when writing code that depends on the collection being loaded into the client minimongo, that you should explicitly subscribe to the collection and pass in the appropriate callback for when it is finished loading.
My problem is that I store a lot of important subdocuments that my page needs to access in the users collection. I am using Meteor Accounts, and am trying to figure out a similar way to wait until the entire logged in user document is available. When using this to test:
console.log(Meteor.user());
the logged in case, it seems like it first registers an object with just the _id, and then sends the other fields later (I know I have to explicitly add other fields to publish from the server beyond email, etc.).
Is there a way for me to wait for the logged in user document to load completely before executing my code?
Thanks!
Deps.autorun (previously Meteor.autorun) reruns when something reactive changes, which might fit your use case:
Client js
Deps.autorun(function () {
if(Meteor.user() {
//Collection available
}
});
If you're using a subscription you can also use its callback. Have a read about it on the docs as you might have to customize it a bit, and remove the autopublish package as well as get your other collections set up to subscriptions
Server js:
Meteor.publish("userdata", function () {
//You might want to alter this depending on what you want to send down
return Meteor.users.find({}, {}});
});
Client js
Meteor.subscribe("userdata", function() {
//Collection available
});