I'm using Meteor 1.0
This probably is a common beginners mistake but I can't seem so find the solution.
When I ask the server to return a collection, the results are not shown. However, I console log shows me the good results.
Here is the client helper:
Template.myProjectTips.helpers({
matchingProjects: function() {
Meteor.call('searchNearProjects', function(error, result) {
if (error) {
console.log(error.reason);
return;
} else {
var fields = [{}];
_.each(result, function(field) {
fields = field;
console.log('result: ' + fields.title);
});
return fields;
}
});
},
});
Can someone help me out with it?
First of all, your method should return a cursor, so you should remove .fetch() which in fact traverses the cursor to return an array. Cursor is natively supported and promoted in Meteor.
Meteor.methods({
searchNearProjects: function() {
return Project.find({}, {sort: {createdAt: -1}, limit: 10});
}
});
Also in your template code, you are replacing your array, instead you should be populating it. But since you are working with a live cursor, you don't need all of that _.each() traversal either. Therefore you can simply do:
Template.myProjectTips.helpers({
matchingProjects: function() {
Meteor.call('searchNearProjects', function(error, result) {
if (error) {
console.log(error.reason);
return;
} else {
return result;
}
});
}
});
But for a very simple Mongo query like this, you should not be using a Meteor.method
Instead you should publishing and subscribing like this:
Server:
Meteor.publish("nearProjects", function () {
return Project.find({}, {sort: {createdAt: -1}, limit: 10});
});
Client:
Meteor.subscribe("nearProjects");
Template.myProjectTips.helpers({
matchingProjects: function() {
return Project.find({}, {sort: {createdAt: -1}, limit: 10});
}
});
Or if you want to publish with some find criteria, you can pass in your arguments to your subscribe and publish functions as well.
Related
I have a problem with updating some values in Meteor app on client-side. I'm trying to understand how ReactiveVar works.
When I use find() method on collection on client-side the site updates immediately each time I change something. I want to achieve the same effect using ReactiveVar and server-side Method. So the code below works correctly for me:
// Client
Template.body.onCreated(function appBodyOnCreated() {
this.subscribe('activities');
}
Template.body.helpers({
getCounter() {
return Activities.find({
editorId: Meteor.userId(),
'referredObject.type': 'LIST'
}).count();
}
});
But when I try to achieve the same effect with server-side Method it doesn't work correctly. Code below updates variable only once. If I want to get current value I need to refresh the page.
// Server
Meteor.methods({'activitiesCreateCount'(userId, objectType) {
check(userId, String);
check(objectType, String);
return Activities.find({
editorId: userId,
'referredObject.type': objectType
}).count();
}
});
// Client
Template.body.onCreated(function appBodyOnCreated() {
this.subscribe('activities');
this.activitiesAmount = new ReactiveVar(false);
}
Template.body.helpers({
getCounter() {
var tempInstance = Template.instance();
Meteor.call('activitiesCreateCount', Meteor.userId(), 'TODO', function(err, response) {
tempInstance.activitiesAmount.set(response);
});
return Template.instance().activitiesAmount.get();
}
});
How I can improve my code if I want always have a current value of the variable (like in the first client-side only example)?
Try to move Meteor.callto Template.body.onCreated
Something like this
// Server
Meteor.methods({'activitiesCreateCount'(userId, objectType) {
check(userId, String);
check(objectType, String);
return Activities.find({
editorId: userId,
'referredObject.type': objectType
}).count();
}
});
// Client
Template.body.onCreated(function appBodyOnCreated() {
self = this;
this.activitiesAmount = new ReactiveVar(false);
Meteor.call('activitiesCreateCount', Meteor.userId(), 'TODO', function(err, response) {
self.activitiesAmount.set(response);
});
}
Template.body.helpers({
getCounter() {
return Template.instance().activitiesAmount.get();
}
});
Using this code in a file "reports.js" in the same folder of "reports.html", I get 0 elements in the array returned. Not sure I am missing any extra declaration but also I can't use "import { Mongo } from 'meteor/mongo';" without having error "Use of reserved word 'import'".
Meteor version 1.2.1
JS
Tasks = new Mongo.Collection('tasks');
if(Meteor.isClient){
Template.reports.rendered = function(){
if(Session.get("animateChild")){
$(".reports-page").addClass("ng-enter");
setTimeout(function(){
$(".reports-page").addClass("ng-enter-active");
}, 300);
setTimeout(function(){
$(".reports-page").removeClass("ng-enter");
$(".reports-page").removeClass("ng-enter-active");
}, 600);
}
};
}
Template.dashboardd.helpers({
options() {
return Tasks.find({});
},
});
HTML
<Template name="dashboardd">
{{#each options}}
<p><label>{{text}}</label></p>
{{/each}}
</Template>
AFAIK meteor 1.2 don't supports Imports. Improrts are new module added i meteor 1.3 or 1.4 im not sure.
I allways use this 3 Elements when work with collections (4 if we take collection declaration)
You should do on server side some publish and allows like:
Meteor.publish("Tasks ", function (selector, options) {
//you can remove condition if you dont have accounts-package
if (this.userId) {
return Tasks .find(selector || {}, options || {});
}
});
And some Allows
Once again if you dont have Meteor-accounts you can simply - return true, on inserts, updates etc. But I don't must say that is not safety :P
Tasks.allow({
insert: function (userId, doc) {
return userId;
},
update: function (userId, doc) {
return userId;
},
remove: function (userId) {
return userId;
},
});
On Client side some subscribe
Template.YourTemplateName.onCreated(function () {
this.autorun(() => {
this.subscribe('Tasks', { _id: Template.currentData()._id });
//or
this.subscribe('Tasks');
//but this solution can kill Browser when you collection will have a thousand elements. Allways try to not subscribe all collection. Only Needed fields/objects
});
});
I'm pretty new to Mongodb and have so far successfully used Find, Insert, Update methods. However, with Delete function I am not able to access WriteResult
Insert (Works)
productCollection.insert(newProduct, function (err, result) {
callBack(err, { message: result["insertedCount"] + ' product created successfully.' });
});
Find (Works)
productCollection.find({}).toArray(function (err, docs) {
callBack(err, { product: docs });
});
Delete (Has Issues)
productCollection.remove({ id: pId }, { justOne: 1 }, function (err, result) {
callBack(err, { message: result});
});
Here when I return {message: result} I get
{
"message": {
"ok": 1,
"n": 0
}
}
But I want to actually read "n" from Result to show no of documents deleted
Tried following
{ message: result["n"] }
{ message: result["nRemoved"] }
But in both cases it returns empty object {}.
According to the 2.0 version of Node.js MongoDB Driver API, remove() method is deprecated, you can use removeOne() method instead:
http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#remove
In order to receive number of documents that were removed, you need to use safe mode to ensure removal of documents. To do this, specify write concern by passing {w: 1} to removeOne() function:
productCollection.removeOne({ _id: pId }, { w:1 }, function(err, r) {
// number of records removed: r.result.n
callBack(err, { message: r });
});
Hope this helps.
Thanks Yelizaveta for pointing out the deprecated method. However in my case, following worked
productCollection.removeOne({ id: pId }, { w: 1 }, function (err, r) {
callBack(err, { message: r.result["n"]});
});
I could not get r.result.n working instead r.result["n"] worked, which I don't understand.
I am writing an app with angular as front end and meteor as back end and I want to retrieve every user in the collection "Users" (added module accounts-ui and accounts-password). But when I execute the following code, it only returns one object (the last added) while there are 3 users.
if(Meteor.isClient){
angular.module('timeAppApp')
.controller('SignInCtrl', function($scope, $meteor, $location) {
$scope.LogIn = function() {
console.log($meteor.collection(Meteor.users).subscribe('users_by_email', $scope.username));
console.log($meteor.collection(Meteor.users).subscribe('all_users'));
};
});
}
if (Meteor.isServer) {
// Returns all users find by email
Meteor.publish('users_by_email', function(emailE){
return Meteor.users.find({'emails.address': emailE});
});
Meteor.publish('all_users', function(){
return Meteor.users.find({}, {fields: {emails: 1}});
})
I'm new to meteor so I'm still experimenting but now I'm really stuck.
Try this,
On server side
Meteor.methods({
get_users_by_email: function (emailE) {
return Meteor.users.find({ emails: { $elemMatch: { address: emailE } } }).fetch();
}
});
On client side
$meteor.call('get_users_by_email', $scope.username).then(
function(data){
console.log('success get_users_by_email', data);
},
function(err){
console.log('failed', err);
}
);
I am try to publish posts created by the usernames in the following array each users has. I am adding this to the microscope practice app The error is I20140826-20:31:53.452(-4)? at Meteor.publish.Comments.find.postId [as _handler] (app/server/publications.js:2:13). Thanks in advanced here is the code.
publications.js
The loop is supposed to publish posts made by each username in the following array.
Meteor.publish('posts', function(options) {
for (u=0;u<this.user.profile.following.length;u++) {
f=profile.following[u].text();
return Posts.find({username:f}, options);
}
});
The Routes it will affect
Controllers
PostsListController = RouteController.extend({
template: 'postsList',
increment: 5,
limit: function() {
return parseInt(this.params.postsLimit) || this.increment;
},
findOptions: function() {
return {sort: this.sort, limit: this.limit()};
},
waitOn: function() {
return Meteor.subscribe('posts', this.findOptions());
},
posts: function() {
return Posts.find({}, this.findOptions());
},
data: function() {
var hasMore = this.posts().count() === this.limit();
return {
posts: this.posts(),
nextPath: hasMore ? this.nextPath() : null
};
}
});
NewPostsListController = PostsListController.extend({
sort: {submitted: -1, _id: -1},
nextPath: function() {
return Router.routes.newPosts.path({postsLimit: this.limit() + this.increment})
}
});
BestPostsListController = PostsListController.extend({
sort: {votes: -1, submitted: -1, _id: -1},
nextPath: function() {
return Router.routes.bestPosts.path({postsLimit: this.limit() + this.increment})
}
});
Router map
this.route('newPosts', {
path: '/new/:postsLimit?',
controller: NewPostsListController
});
this.route('bestPosts', {
path: '/best/:postsLimit?',
controller: BestPostsListController
});
Your publish function is wrong, are you aware that your loop is useless because it is exiting upon encountering the first return ?
Even if you were aggregating the cursors accumulated in the loop this wouldn't work because at the moment a publish function can only return multiple cursors from DIFFERENT collections.
You need to use the appropriate mongo selector here, which is probably $in.
Also, profile.following is not even defined in the publish function, and iterating over an array is done by checking the iterator variable against the array length (profile.following.length), or better yet using Array.prototype.forEach or _.each.
I think this is what you're trying to do :
Meteor.publish("posts",function(options){
if(!this.userId){
this.ready();
return;
}
var currentUser=Meteor.users.findOne(this.userId);
return Posts.find({
username:{
$in:currentUser.profile.following
}
},options);
});
You should definitely read resources about JavaScript itself before digging any further in Meteor, if you're following the Discover Meteor book I think they provide some good JS tutorials for beginners.