returning embedded document from collection find - meteor

This Meteor code tries to return a cursor to the embedded documents referenced by the field data, then checks if it exists (because some times it does not exist in ActiveTaskCol) before returning this template helper method.
added later
The expected returned cursor will be used in the html {{#each data}} for more work hence the use of .find instead of .findOne.
The problem is that the if statement evaluates to true even though there is no data field in the ActiveTaskCol, I also tried obj.count() > 0 which also true even though "data" field does not exist in the collection.
How can I fix this? Thanks
Template.index.helpers({
taskInputs: function () {
var ready = Meteor.subscribe('inputsCol').ready();
var data = InputsCol.find({});
var selectedTask = Session.get('taskSelected');
var obj = ActiveTaskCol.find({action: selectedTask}, {field: {data: 1}});
if (typeof obj != 'undefined') { //<-always true --------------
return {items: obj};
} else {
return {items: data, ready: ready};
}
}
});

It is always true because, you are using find, which returns a cursor. Instead, you should use findOne, so that, it will return document or undefined, if there is no such document. I also suggest, you use obj, which checks for falsy values like undefined, null, false instead of typeof obj != 'undefined'
Template.index.helpers({
taskInputs: function () {
var ready = Meteor.subscribe('inputsCol').ready();
var data = InputsCol.find({});
var selectedTask = Session.get('taskSelected');
var obj = ActiveTaskCol.findOne({action: selectedTask}, {field: {data: 1}});
if (obj) {
return {items: obj};
} else {
return {items: data, ready: ready};
}
}
});
Update:
Based on your comments, you can use obj.count() to check whether there are documents matching your criteria.
Template.index.helpers({
taskInputs: function () {
var ready = Meteor.subscribe('inputsCol').ready();
var data = InputsCol.find({});
var selectedTask = Session.get('taskSelected');
var obj = ActiveTaskCol.find({action: selectedTask}, {field: {data: 1}});
if (obj.count() > 0) {
return {items: obj};
} else {
return {items: data, ready: ready};
}
}
});
Update 2
Template.index.helpers({
taskInputs: function () {
var ready = Meteor.subscribe('inputsCol').ready();
var data = InputsCol.find({});
var selectedTask = Session.get('taskSelected');
var obj = ActiveTaskCol.find({
action: selectedTask,
data: { $exists: true }
}, {
field: {data: 1}
});
if (obj.count() > 0) {
return {items: obj};
} else {
return {items: data, ready: ready};
}
}
});

Related

ngservice method called automatically and application stopped

my application have some dropdowns and one search button.after selection from dropdown click search button. It will display result based on selected values. I am using web api to fetch data from database. angular service will call those api methods
//for family dropdown
this.getProresultByseriesFamily = function (family) {
var res;
if (family !== 0) {
res = $http.get("/api/KendoCascading/GetProresult/" + family);
return res;
}
};
//for class dropdown
this.getFuseClassRes = function (fuseClass) {
var res;
if (fuseClass !== null) {
res = $http.get("/api/KendoCascading/GetResFuse/" + fuseClass);
return res;
}
};
//for series dropdown
this.getresSeries = function (seID) {
var res;
if (seID !== 0) {
res = $http.get("/api/KendoCascading/GetSeriesResult/" + seID);
return res;
}
};
controller
$scope.getProResult = function () {
if ($scope.SelectedCriteria != null || $scope.SelectedCriteria!="") {
var promise = ngservice.getProresultByseriesFamily($scope.SelectedCriteria);
promise.then(function (resp) {
console.log(resp.data);
$scope.Products = resp.data;
alert("successful1");
}, function (err) {
alert("Falied");
});
}
if ($scope.FuseModel != null || $scope.FuseModel != "") {
var promise = ngservice.getFuseClassRes($scope.FuseModel);
promise.then(function (resp) {
$scope.Products = resp.data;
alert("successful2");
}, function (err) {
alert("failed");
});
}
if ($scope.FuseSeriesModel != null || $scope.FuseSeriesModel != "") {
var promise = ngservice.getresSeries($scope.FuseSeriesModel);
promise.then(function (resp) {
$scope.Products = resp.data;
alert("successful");
}, function (err) {
alert("Failed");
});
}
};
this controller function used as a click event in view. If i call first service method the view populate the result. But after some time it is automatically calling the 3rd service method and application stopped working. What is going wrong? if any better solution exist please help me.
api is working fine . i have checked in browser. It is fine.
view
<Button type="button" ID="Btn_Search" Width="90" Class="btn btn-primary btn-sm" ng-click="getProResult();show=!show">Search</Button>
I think the problem is because sometimes your service returns undefined.
In the third case, which is the one with problem, if $scope.FuseSeriesModel === 0, ngservice.getresSeries($scope.FuseSeriesModel) will return undefined and it will throw an error because you are calling then on undefined.
I would recommend you to update your code to check for the promise before calling .then.
For example:
if ($scope.FuseSeriesModel != null || $scope.FuseSeriesModel != "") {
var promise = ngservice.getresSeries($scope.FuseSeriesModel);
if (promise) {
promise.then(function (resp) {
$scope.Products = resp.data;
alert("successful");
}, function (err) {
alert("Failed");
});
}
}
Another way is to update your if conditions to !!$scope.FuseSeriesModel (or Boolean($scope.FuseSeriesModel)). That way, your promise code will be called only when the value is Truthy which I think is what you really want to do:
if (Boolean($scope.FuseSeriesModel)) { // or $scope.FuseSeriesModel or !!$scope.FuseSeriesModel
var promise = ngservice.getresSeries($scope.FuseSeriesModel);
promise.then(function (resp) {
$scope.Products = resp.data;
alert("successful");
}, function (err) {
alert("Failed");
}
);

Create a universal helper variable

Is there a way to create a variable at the top of template helpers to remove duplication.
In this particular situation I'm using var candidate = FlowRouter.getParam('id'); and I have to create the variable in each helper. I assume there is a better way.
professionalOverview: function() {
var candidate = FlowRouter.getParam('id');
return ProfessionalOverview.findOne({ candidateUserId: candidate });
},
candidateImg: function() {
var candidateUserId = FlowRouter.getParam('id');
return Files.findOne({ userId: candidateUserId });
},
EDIT
Template.talentProfileNew.onCreated(function() {
var self = this;
self.autorun(function(){
this.candidateUserId = new ReactiveVar(FlowRouter.getParam('id'));
}
});
Template.talentProfileNew.helpers({
candidate: function() {
console.log(Template.instance().candidateUserId.get());
return Meteor.users.findOne({_id: Template.instance().candidateUserId.get()});
}
});
you could read it once in onCreated() and put it in a reactive var. e.g.
Template.Foo.onCreated(function() {
this.candidateUserId = new ReactiveVar(FlowRouter.getParam('id'));
});
Template.Foo.helpers({
candidateImg() {
return ProfessionalOverview.findOne({ userId: Template.instance().candidateUserId.get()});
}
});

How come this isn't working Sync/Async issues with Meteor.methods

This is weird but when I call a external function from Meteor.method function it will always return undefined in the client I tried Meteor.wrapAsync but I think I'm doing something wrong. Here is my code:
var demoFunction = function () {
//database operations
var user = this.userId;
if (!user)
return;
var count = Users.aggregate([
{ $group: {_id: null, count: {$sum: 1}} }
]);
if (count[0] && count[0].count)
return count[0].count;
return 0;
}
Meteor.methods({
// NOT WORKING, How can I make this work?
methodDemo: function () {
var result = demoFunction ();
return result;
},
// Works
methodDemo2: function () {
//database operations
var user = this.userId;
if (!user)
return;
var count = Users.aggregate([
{ $group: {_id: null, count: {$sum: 1}} }
]);
if (count[0] && count[0].count)
return count[0].count;
return 0;
}
});
// Call from client
Meteor.call("methodDemo", function (err, res) { });
calling external functions doesn't work the same way if I put the code inside the meteor method why?
Try using Meteor.userId() in your function instead of this.userId. I think you are loosing the value of this when calling your function causing it to exit early.
Since you declared the function with a var it is scoped outside of methodDemo().
You could declare the function globally by removing var or move the demoFunction() code into methodDemo().

Weird undefined error on server

I have the following meteor method
hasNoPendingPayments: function() {
var userId = Meteor.userId();
console.log(userId); <---------------------- correctly logs userId
var user = Users.findOne({_id: userId }, { fields: { services: 0 } });
console.log(user); <-------------------------- logs 'undefined'
return hasNoPendingPayments(user);
},
This private helper I call from the above
hasNoPendingPayments = function(user) {
// console.log('hasNoPendingPayments ');
// console.log(user);
var payments = Payments.find({ userId: user._id, status: {
$in: [Payments.States.PENDING, Payments.States.PROCESSING]}
});
return payments.count() === 0;
};
And I call it from the client here
Template.payments.created = function() {
this.hasNoPendingPayments = new ReactiveVar(false);v
};
Template.payments.rendered = function () {
Session.set('showPaymentRequestForm', false);
var self = this;
Meteor.call('hasNoPendingPayments', function(error, result) {
if (result === true) { self.hasNoPendingPayments.set(true); }
});
...
However, I get an undefined error on the server when I load the template initially (I marked where in code). Although, when I try call the same query on the client with the same userId, i correctly gets the user record
Any idea as to why this is?
Try with this.
Template.payments.rendered = function () {
Session.set('showPaymentRequestForm', false);
var self = this;
if(Meteor.userId()){
Meteor.call('hasNoPendingPayments', function(error, result) {
if (result === true) { self.hasNoPendingPayments.set(true); }
});
}else{
console.log("Seems like user its not logged in at the moment")
}
Maybe when you make the Meteor.call, the data its not ready
Also just to be sure, when you run Users.findOne({_id: userId }, { fields: { services: 0 } }); on console.log what you get?
Maybe the find is wrong or have some typo
update
Router.map(function()
{
this.route('payments',
{
action: function()
{
if (Meteor.userId())
this.render();
} else{
this.render('login') // we send the user to login Template
}
}
}
or waitOn
Router.map(function () {
this.route('payments', {
path: '/payments',
waitOn: function(){
return Meteor.subscribe("userData"); //here we render template until the subscribe its ready
}
});
});
Meteor stores all the user records in Meteor.users collection
so try Meteor.users.findOne({_id: userId }....)
Instead of Users.findOne({_id: userId }, { fields: { services: 0 } });
in your server method

Firebase on() does not return anything

I have this piece of code using on() to get data from Firebase, inside on() I create object which I want to send out of function for future use - using return, but it seems it doesn't return anything.
So question is how can I make it right?
postsRef.on('value', function(snapshot) {
if (snapshot.val() === null) {
var allPosts = false,
numberOfPosts = 0;
}
else {
var allPosts = snapshot.val(),
numberOfPosts = Object.size(allPosts);
}
var postsData = {
content: allPosts,
count: numberOfPosts
};
return postsData;
});
The callback function is called asynchronously (some time in the future). So by the time it is invoked, postsRef.on(...) has already returned and any code immediately after it will have run.
For example, this might be tempting, but would not work:
var postsData;
postsRef.on('value', function(snapshot) {
postsData = snapshot.val();
});
console.log(postsData); // postsData hasn't been set yet!
So there are a few different ways to tackle this. The best answer will depend on preference and code structure:
Move the logic accessing postsData into the callback
postsRef.on('value', function(snapshot) {
postsData = snapshot.val();
console.log(postsData);
});
Call another function when the callback is invoked
function logResults(postsData) {
console.log(postsData);
}
postsRef.on('value', function(snapshot) {
logResults(snapshot.val());
});
Trigger an event
function Observable() {
this.listeners = [];
}
Observable.prototype = {
monitorValue: function( postsRef ) {
var self = this;
postsRef.on('value', function(snapshot) {
self._notifyListeners(postsRef);
});
},
listen: function( callback ) {
this.listeners.push(callback);
},
_notifyListeners: function(data) {
this.listeners.forEach(function(cb) {
cb(data);
}
}
};
function logEvent( data ) {
console.log(data);
}
var observable = new Observable();
observable.listen( logEvent );
observable.monitorValue( /* postsRef goes here */ );

Resources