Subcribe gets more records than server publishes - meteor

I am trying to publish all admin users from server
on server something like this:
Meteor.publish("users_with_roles", function (options, role) {
//{fields: {emails: 1, profile: 1}}
Counts.publish(this, 'numberOfUsers', Meteor.users.find({$and:[
{'roles.tripro': {$exists: true}},
{'roles.tripro': role}
]}),
{ noReady: true });
return Meteor.users.find({
$and:[
{'roles.tripro': {$exists: true}},
{'roles.tripro': role}
]
}, options);
});
Then on client side, I am trying to subscribe this:
$meteor.autorun($scope, function() {
$meteor.subscribe('users_with_roles', {
limit: parseInt($scope.getReactively('perPage')),
skip: (parseInt($scope.getReactively('page')) - 1) * parseInt($scope.getReactively('perPage')),
sort: $scope.getReactively('sort'),
fields: {emails: 1, profile: 1}
},'admin').then(function() {
$scope.usersCount = $meteor.object(Counts ,'numberOfUsers', false);
console.log('user counter:' + $scope.usersCount.count);
$scope.users.forEach( function (user) {
// user.onClicked = function () {
// //$state.go('userProfile', {userId: user._id});
// };
console.log(user._id);
});
},
function(error)
{
console.log(error);
}
);
});
$scope.users = $meteor.collection(function() {
console.log('looking for role: ' + role);
return Meteor.users.find({}, {
//sort : $scope.getReactively('sort')
});
});
However, from the logging, it appears that the client side received all users , but from the logging on server side, it does give correct result.
What am I missing here?

A couple things to think about here.
When you request users you will always have "you". So if the user you are logged into is not an admin, it will still show up in the collection.
Because you are using $meteor.subscribe instead of $scope.$meteorSubscribe you are not clearing the subscription when the scope is destroyed so it's possible that it's mixing with other subscriptions on the client side from other scopes.

Related

Publish users using id from a different collection

I'm trying to access the userIds stored in a collection and then use them to publish the details of all of the meteor.users. My publish function doesn't isn't return anything?
Meteor.publish('allUsersWithOffers', function () {
var user = Offers.find({}, {fields: {"UserId": 1}});
return Meteor.users.find({_id: user});
});
Give this a try:
Meteor.publish('allUsersWithOffers', function () {
var offers = Offers.find({}, { fields: { UserId: 1 } }).fetch();
var ids = _.pluck(offers, 'UserId');
// This is critical - you must limit the fields returned from
// the users collection! Update this as needed.
options = { fields: { username: 1, emails: 1 } };
return Meteor.users.find({ _id: { $in: ids } }, options);
});
find returns a cursor - you need to call fetch to actually get the documents.

Overlapping subscription does not publish all fields

When I have two subscriptions that limit the fields to publish it does not do a union between the two
This should publish only the avatar.
Meteor.publish('userStatisticsByYear', function(year) {
check(year, Number);
this.unblock();
var userStats = UserStatistics.find({year: year},{sort: {count: -1}, limit: 5});
var userIds = userStats.map(function(u) {
return u.userId;
});
return [
Meteor.users.find({_id: {$in: userIds}},{fields: {username: 1, "profile.avatar": 1}}),
ProfileImages.find({owner: {$in: userIds}}),
userStats
];
});
And this subscription publishes more details of the profile. Which is fine under some routes.
Meteor.publish('getUserProfile', function(userId) {
this.unblock();
if (!this.userId) {
this.ready();
return;
}
return [
Meteor.users.find({_id: userId}, {fields: {profile: 1}}),
ProfileImages.find({owner: userId})
]
});
The problem is that if I subscribe to both only "profile.avatar" is being published. But not the extra fields from "getUserProfile"
The output of the console:
Meteor.subscribe('userStatisticsByYear')
Object {subscriptionId: "aQFv4HkGDKx54gJLq"}
Meteor.users.findOne("KABEf7SzNCmQapXND").profile
Object {avatar: "NQokwm9bHgfrMtKLY"}
Meteor.subscribe('getUserProfile','KABEf7SzNCmQapXND')
Object {subscriptionId: "hemH2NF88vwd3AkHv"}
Meteor.users.findOne("KABEf7SzNCmQapXND").profile
Object {avatar: "NQokwm9bHgfrMtKLY"}
I have seen this before.
if you use Meteor.users.find({"_id":"KABEf7SzNCmQapXND"}).profile instead of findOne, I believe it should work.

Client data not being updated in Meteor application

I have a Meteor application with a publish of:
Meteor.publish('my_items', function() {
var selector = {owner_id: this.userId};
var items = ItemOwnership.find(selector, {fields: {item_id: 1}}).fetch();
var itemIds = _.pluck(items, 'item_id');
return Items.find({
_id: {$in: itemIds},
item_archived_ts: { $exists: false }
});
});
and a subscription of this:
Meteor.subscribe('my_items');
The application allows for the user to add items to the 'Items' collection and this is done by calling a server method. The Items collection on the server is updated with the new record, but the client-side equivalent collection is not showing the new record. Is there anything obviously wrong with what I am doing, or some way to debug this?
p.s. there are no client/server-side errors occurring?
I found a way to accomplish this using the reywood:publish-composite Meteor package. Here is the publish that achieves this:
Meteor.publishComposite('my_items', {
find: function () {
var selector = {owner_id: this.userId};
return ItemOwnership.find(selector, {fields: {item_id: 1}});
},
children: [
{
find: function(IOrecord){
return Items.find({
_id: IOrecord.item_id,
item_archived_ts: { $exists: false }
});
}
}
]
});

Meteor.User does not load with all fields on initial load

I have added an additional field on Meteor.Users collection called usertype. In Iron-router I am returning the user object if user is logged in. Now in my template I need to check if this usertype field is present else, I direct the user to user registrations screen.
What is happening here is that even though I have the usertype field in my publish function, the user object is not returned with this field initially. It only shows up after 2-3 object loads. And this confuses the template loading logic, as this field is not found on initial load, but when infact the field is present.
DashboardController = RouteController.extend({
template: 'dashboard',
subscriptions: function() {
this.userProfileSub = Meteor.subscribe('singleUser', this.myId());
},
myId: function() {
var userId = Meteor.userId();
if(!userId)
{ userId = ''; }
return userId;
},
user: function() {
return Meteor.users.findOne(this.myId());
},
data: function() {
var user = this.user();
console.log(user);
if(user)
{
return {
user: this.user(),
ready: this.userProfileSub,
};
}
}
});
Here is the publish method:
Meteor.publish('singleUser', function(id) {
check(id, String);
return Meteor.users.find({_id:id}, {fields: { emails: 1,
profile: 1,
usertype: 1,
"services.facebook.id": 1,
"services.facebook.email": 1,
"services.twitter.screenName": 1,
"services.twitter.profile_image_url": 1,
"services.google.email": 1,
"services.google.picture": 1}});
});
EDIT
As answer given below, if the subscription is moved inside the waitOn block it should wait for the subscription to load completely.
waitOn: function() {
this.userProfileSub = Meteor.subscribe('singleUser', this.myId());
return [this.userProfileSub];
},
But now when I try to wait for multiple subscriptions to load in the wait array, it apparently is not waiting for all of them. I still get empty array. Even though I check in the action block. I can find the data later from my console.
waitOn: function() {
return [
Meteor.subscribe('singleUser', this.myId()),
Meteor.subscribe('singleAgentByUserId', this.myId()),
Meteor.subscribe('singleClientByUserId', this.myId())];
},
action: function () {
// this.ready() is true if all items returned from waitOn are ready
if (this.ready())
{
this.render();
}
else
this.render('Loading');
},
Update EDITED (See revision history for much different version due to original question)
Try:
waitOn: function() {
return [
Meteor.subscribe('singleUser', Meteor.userId()),
Meteor.subscribe('singleAgentByUserId', Meteor.userId()),
Meteor.subscribe('singleClientByUserId', Meteor.userId()];
},
loadingTemplate: "loading",
action: function () {
this.render('dashboard');
}

Unable to pass result to router after calling Meteor.methods

I encounter an error using Meteor. I call an Method.method.
Template.WelcomeTemplate.events({
'click #btn-findgame': function(e) {
e.preventDefault();
console.log('clicked find game button');
Meteor.call('allocateGame', function(error, id) {
if (error) {
alert(error.reason);
} if (id) {
Router.go('gameRoom', {_id: id})
}
})
}
})
With my Method, I check if there is an room available, create one when the isn't otherwise join. And return the ID of this room.
Meteor.methods({
allocateGame: function () {
console.log('allocateGame method called')
var user = Meteor.user();
// find game where one player is in the room
var gameWaiting = Games.findOne({players: {$size: 1}})
if (!gameWaiting) {
console.log('no game available, create a new one');
var newGameId = Games.insert({players: [user._id], active: false, finished: false});
GameDetails.insert({gameId: newGameId, gameData: []});
return newGameId
} else {
if (_.contains(gameWaiting.players, user._id)) {
console.log('Cannot play against yourself sir')
} else {
console.log('Joining game');
Games.update({_id: gameWaiting._id}, {
$set: {active: true},
$push: {players: user._id}
});
return gameWaiting._id;
}
};
}
})
And my Router:
Router.map(function () {
this.route('welcome', {
path: '/',
controller: WelcomeController})
this.route('gameRoom', {
path: '/game/_:id'
})
});
The Error I recieve is:
Exception in delivering result of invoking 'allocateGame': TypeError: Cannot read property 'charAt' of null
at Object.IronLocation.set (http://localhost:3000/packages/iron-router.js?e9fac8016598ea034d4f30de5f0d356a9a24b6c5:1293:12)
And indeed, If I don't return an ID the Routing will continue as normal. However when I return an ID in my WelcomeTemplate an error will occur.
EDIT:
Even thought my MongoDB is updating my MiniMongo DB is empty. There must be a problem with syncing. Any idea where to look?
In the route, you set the path to be '/game/_:id', that is, a parameter with the name id. In your call to Router.go, you pass a parameter with the name _id.
Don't know if this solves your problem, but it's an error.
This kind of embarrassing taking in account how many hours I've spent on fixing this. The error was created because of an error in my routers.js
this.route('gameRoom', {
path: '/game/_:id'
})
Should be:
this.route('gameRoom', {
path: '/game/:_id'
})
Happy coding.

Resources