Why aren't updates to my mongodb query NOT always reflecting? - meteor

I have a Sessions.get() in my MongoDB query. This means the displayed collection depends on the Sessions.get() value. To give you a clearer image of what I mean, find below what my query looks like:
Template.paymentB2C.onCreated( function(){
Session.set('pendingFilter', [ "Pending", "Failed", "Success" ]);
});
.
Template.paymentB2C.helpers({
'showTransactions': function(){
var transactions = paymentDetails.find({
paymentStatus:{$in: Session.get('Filter')}
}).fetch();
return transactions;
}
});
The above code displays a list of transactions. The displayed list of transactions varies in types of transactions suggesting: Failed, Successful, to Pending transactions as seen more accurately below:
0:
payersName: "Sa Acea"
paymentStatus: "Success"
_id: "D3gY4BoR2tvxdK4xv"
1:
payersName: "Paul Acea"
paymentStatus: "Pending"
_id: "ajCjYbLaDP7x4iAFK"
2:
payersName: "Simon Bolton"
paymentStatus: "Success"
_id: "K4d6wDrjRRdSyCkhW"
I, therefore, use the Filter Session values as a Filter to dictate what types of transactions to display.
I am able to interchange between the three types of Filters via the below events. Find below the code.
Template.paymentB2C.events({
'click .ShowFailedTransactions' (event, instance) {
event.preventDefault();
Session.set('Filter', [ "Failed" ]);
},
'click .ShowSuccessfulTransactions' (event, instance) {
event.preventDefault();
Session.set('Filter', [ "Success" ]);
},
'click .ShowPendingTransactions' (event, instance) {
event.preventDefault();
Session.set('Filter', [ "Pending" ]);
},
});
Note that there isn't a Failed transaction type in the collection. So I find it very strange that whenever I choose the Failed filter 'click .ShowFailedTransactions' expecting the desired effect to be a blank empty page, the page fails to update and continues to the show the results of the previous query, as if I never clicked 'click .ShowFailedTransactions'.
I thought perhaps the Session.set('Filter', [ "Failed" ]) in the 'click .ShowFailedTransactions' function wasnt working, so I added a console.log(); to print out the Filter Session value as seen below:
'click .ShowFailedTransactions' (event, instance) {
event.preventDefault();
Session.set('Filter', [ "Failed" ]);
var displaySession = Session.get('Filter');
console.log("Filter Value is: " +displaySession );
},
The above code yields Filter Value is: Failed in the browser console, suggesting that the Filter session value gets updated as expected.
I am confused, to why the page will not respond/update to this.
Kindly help suggest a solution for this issue.

The problem in your code is the fetch, it's not reactive! The good news is that you don't need it. Try this:
Template.paymentB2C.helpers({
'showTransactions': function(){
return paymentDetails.find({paymentStatus: {$in: Session.get('Filter')}});
}
});

Related

meteor autocomplete server-side

I'm writing a meteor app and I'm trying to add an autocomplete feature to a search box. The data is very large and is on the server, so I can't have it all on the client. It's basically a database of users. If I'm not wrong, the mizzao:autocomplete package should make that possible, but I can't seem to get it to work.
Here's what I have on the server:
Meteor.publish('autocompleteViewers', function(selector, options) {
Autocomplete.publishCursor(viewers.find(selector, options), this);
this.ready();
});
And here are the settings I use for the search box on the client:
getSettings: function() {
return {
position: 'bottom',
limit: 5,
rules: [{
subscription: 'autocompleteViewers',
field: '_id',
matchAll: false,
options: '',
template: Template.vLegend
}],
};
}
But I keep getting this error on the client:
Error: Collection name must be specified as string for server-side search at validateRule
I don't really understand the problem. When I look at the package code, it just seems like it's testing whether the subscription field is a string and not a variable, which it is. Any idea what the problem could be? Otherwise is there a minimum working example I could go from somewhere? I couldn't find one in the docs.
Error: Collection name must be specified as string for server-side search at validateRule
You get this error because you don't specify a Collection name in quotes.
getSettings: function() {
return {
position: 'bottom',
limit: 5,
rules: [{
subscription: 'autocompleteViewers',
field: '_id',
matchAll: false,
collection: 'viewers', // <- specify your collection, in your case it is a "viewers" collection.
options: '',
template: Template.vLegend
}],
};
}
For more information please read here.
Hope this helps!

Update Mongo on the client using document ID, but limiting search with another field

When updating a document which contains an array of objects, I have this function:
Template.editCompetition.events = {
'click button.promote': function() {
Competitions.update({_id: Session.get('competition_id'), 'players.user_id': this.user_id}, {$set: {'players.$.supervisor': true}});
},
};
I am seeing the error:
Uncaught Error: Not permitted. Untrusted code may only update documents by ID.
My document looks like this:
{
_id: 'aaaabbbbb',
title: 'ccccdddddd',
players: [
{
username: 'wwwww',
user_id: 'xxxxx',
supervisor: false
},
{
username: 'yyyyy',
user_id: 'zzzzz',
supervisor: false
}]
}
Isn't my query updating the document by the ID, but also searching for that array position to use the .$ notation.
How can I achieve this without using a method, which seems a bit hacky...?
You are also trying to use the player.user_id as second parameter for update query
Other option you can have to use Meteor.method.
Move Collection update code to Meteor server side method and call it from client side
On Server side,
Meteor.methods({
`update_players`: function(competition_id){
user_id = this.userId
Competitions.update({_id: competition_id, 'players.user_id': user_id}, {$set: {'players.$.supervisor': true}});
}
})
In in above code, understand use of how we fetched current userId with this.userId
and now from your click handler call this meteror method
Meteor.call('update_players')
Hope this helps

Iron Router: My Subscription Doesn't Work Inside waitOn

I have a simple subscription running in Iron Router.
#route 'AdminEditor',
path: '/admin/editor/:id?'
controller: 'AdminController'
template: 'AdminRoot'
yieldTemplates:
'AdminEditor': { to: 'adminAside' }
waitOn: ->
return Meteor.subscribe 'getArticle', #params.id
The publication:
Meteor.publish 'getArticle', (id) ->
return Articles.find { 'id': id }
My database is not empty and have a single document into it:
db.articles.find().pretty()
{
"authors" : [
"dqbxgrxzehXXTbFgG"
],
"date" : ISODate("2014-10-01T20:07:48.846Z"),
"title" : "Meteor #5",
"content" : "hello",
"id" : 1,
"_id" : "WL7ygMw2jL9WnmRYZ"
}
But when I go to /admin/editor/1 and type in my chrome debugger Articles.findOne(), it doesn't return anything. I also have defined the collection in a lib folder:
#Articles = new Meteor.Collection 'articles' # run on both client and server
I know there is probably a little thing I forgot, but the subscription seems to work: when I subscribe to it from the chrome debugger and do a find, it returns the object.
Meteor.subscribe('getArticle', 1);
Articles.findOne();
Can you log the value of #params.id in the waitOn to check what you're actually sending? It could be the fact that you're sending it as a string rather than an integer (as you are in the console). If so, you just need to parseInt and it should work.

Stuck on loading template

Hey I have a system where a logged in user can be in a "battle" and as soon as they are, I want the user to be locked on a given template, until the battle is done.
I have
#
# Currently active battle
#
Meteor.publish 'activeBattle', ->
character = Characters.findOne(userId: this.userId)
if this.userId and character
return Battles.find({active: true, $or: [{characterOneId: character._id}, {characterTwoId: character._id}]})
else
return
and in my iron-router
Router.configure
layoutTemplate: 'layout'
loadingTemplate: 'loading'
waitOn: [
Meteor.subscribe('activeBattle')
]
...
redirectToActiveBattle = (pause) ->
battle = Battles.findOne(active: true)
if battle and Meteor.userId()
throwError('You have a battle in progress.')
Router.go('combat', {_id: battle._id})
pause()
...
Router.onBeforeAction(redirectToActiveBattle, except: ['login', 'logout', 'signup', 'combat'])
This works when the user is logged in and has a character, but if not, the page is stuck on the loading template, instead of displaying the login screen
Actually, you should use this.ready(); instead of an empty return if you don't want to return anything in a publication. So the right way to do the publication could be:
Meteor.publish 'activeBattle', ->
character = Characters.findOne(userId: this.userId)
if this.userId and character
return Battles.find({active: true, $or: [{characterOneId: character._id}, {characterTwoId: character._id}]})
this.ready()

Meteor removes collection on new route

I have a simple list and details view using two collections.
When I navigate back to the list view Meteor removes the single document added to the details collection and undoes the change to the other collection.
I want this data to remain so the client doesn't have to keep reloading it...
Both the 'league' and the 'standings' subscriptions are 'undone' on navigation back to the the root. The league and leagues route both use the 'weeks' Mongo collection. When navigating to a league detail I add to the single document. Navigation to the detail works fine ... its when I navigate back to the list that I loose the collection data.
I need all this data 'cached' and am obviously not going about it correctly....
Router.map(function () {
this.route('leagueList', {
path: '/'
});
this.route('league', {
path: '/league/:league',
template: 'standings',
waitOn: function () {
console.log(this.params.league);
return [Meteor.subscribe('league', this.params.league),
Meteor.subscribe('standings', this.params.league) ];
},
data: function () {
return {theLeague: Leagues.findOne({league: this.params.league}),
theStandings: Standings.findOne()};
}
});
});
Server:
Meteor.publish('leagues', function(){
console.log('all league names sent');
return Leagues.find({}, {fields: {weeks: 0}});
});
Meteor.publish('league', function(theLeague){
console.log('sending weeks detail for: ' + theLeague);
return Leagues.find({league: theLeague});
});
Meteor.publish('standings', function(theLeague){
console.log('standings: ' + theLeague);
var file = Leagues.findOne({league: theLeague}).weeks[0].file;
return Standings.find({file: file});
});
client:
Leagues = new Meteor.Collection('weeks');
Standings = new Meteor.Collection('details');
Meteor.subscribe('leagues');
There's work in progress in iron router to allow (and optimize) this (not immediately stopping the subscriptions when you route to another page). See the sub-manager branch.
But if you create the subscription apart from the waitOn call, I think the subscription is never stopped. For example, in the code below, the routes a and c will wait for the initialData to be received (which will be fetched directly when the user loads the page (even if it uses route b)), and the subscription for it will never stop, even if you leave, for example, route a. However, I don't think you can use this approach if you need to use some parameters in the route (you can probably fix something with setInterval, but it will be ugly).
var handleToDataIMostlyNeed = Meteor.subscribe('initialData')
Router.map(function(){
this.route('a', {
waitOn: function(){
return handleToDataIMostlyNeed
}
})
this.route('b', {
waitOn: function(){
return [] // Wait for nothing.
}
})
this.route('c', {
waitOn: function(){
return handleToDataIMostlyNeed
}
})
})

Resources