In my Meteor app I am trying to receive a limited number of users (on the server!). Of those users I only want to receive a few specified fields.
Why does this query not work as expected?
const users = Meteor.users.find(
{
'roles.__global_roles__': {$in: ['myRole']},
$and: query
},
{fields: {
username: 1,
firstName: 1,
lastName: 1,
update: 1
}},
{
limit: 2,
sort: {'update.any': -1}
}
).fetch();
With this query, limit and sort are ignored. Only the selected fields are received.
I then tried this:
const users = Meteor.users.find(
{
'roles.__global_roles__': {$in: ['myRole']},
$and: query
},
{
limit: 2,
sort: {'update.any': -1}
}
).fetch();
Now limit and sort works but obviously I get the whole user object with all fields.
What is the solution to combining both?
Thanks
find() has 2 parameters, you're providing 3 in your first example. try this:
const users = Meteor.users.find(
{
'roles.__global_roles__': {$in: ['myRole']},
$and: query
},
{fields: {
username: 1,
firstName: 1,
lastName: 1,
update: 1
},
limit: 2,
sort: {'update.any': -1}
}
).fetch();
iow, fields, limit, and sort are all part of the same JSON object as the 2nd argument.
Related
i need to get user details with post count(Number of posts for today).
const usersWithCount = await prisma.user.findMany({
select: {
_count: {
select: {
posts: {
where: {
createdAt: moment().format("YYYY-MM-DD"),
},
},
recipes: true,
},
},
},
})
You cannot filter in relations count, this is not currently supported by prisma.
Here is the Feature Request for adding filters in relations count.
In your use case you can get filtered relations as described below:
const usersWithCount = await prisma.user.findMany({
select: {
posts: {
where: {
createdAt: moment().format("YYYY-MM-DD"),
},
},
recipes: true
},
});
In the response of the above query you will get posts array with records satisfying your where condition, you can use the array's length as a count.
Im publishing my current user this this:
Meteor.publish('currentUser', function() {
return Meteor.users.find(
{ _id: this.userId },
{ fields: { groups: 1, name: 1 } },
);
});
Its working but I belive that findOne is more efficient. The following console.log works but returning Meteor.users.findOne doens't work:
Meteor.publish('currentUser', function() {
const test = Meteor.users.findOne(
{},
{ fields: { groups: 1, events: 1, name: 1 } },
);
console.log(test); // this works
// This doesn't work
return Meteor.users.findOne(
{},
{ fields: { groups: 1, events: 1, name: 1 } },
);
});
The Meteor docs states that the publication should be either of 2 things:
A cursor
An array of cursors (of different collections)
Publish functions can return a Collection.Cursor, in which case Meteor
will publish that cursor’s documents to each subscribed client. You
can also return an array of Collection.Cursors, in which case Meteor
will publish all of the cursors.
findOne returns a document. So I suppose it won't work.
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.
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.
Up and downvotes are functional yet I'd like to do a check like "If the user is a downvoter or an upvoter" and do the right thing which is explained below
upvote: function(postId) {
check(this.userId, String);
check(postId, String);
var affected = Posts.update({
_id: postId,
upvoters: {$ne: this.userId}
},{
$addToSet: {
upvoters: this.userId
},
$inc: {
upvotes: 1
}
});
if (! affected)
throw new Meteor.Error('invalid', "You already up-voted this post");
},
downvote: function(postId) {
check(this.userId, String);
check(postId, String);
var affected = Posts.update({
_id: postId,
downvoters: {$ne: this.userId},
}, {
$addToSet: {
downvoters: this.userId
},
$inc: {
downvotes: 1
}
});
if (! affected)
throw new Meteor.Error('invalid', "You already down-voted this post");
},
With my code above, users can upvote and downvote once, but they can do both...
I wrote the code for what happens if a user is a downvoter and clicks upvote but I couldn't figure out how to check if the user is a downvoter or an upvoter.
$pull: {
downvoters: this.userId
},
$addToSet: {
upvoters: this.userId
},
$inc: {
downvotes: -1
},
$inc: {
upvotes: 1
});
EDIT: Even though the accepted answer works fine, I found an issue with it. When you click fast, it might increment the vote count 2-3 times. Instead of incrementing vote count, I only insert userId and simply count how many IDs there are inside the upvoters/downvoters array which gives the same result & it never inserts the same userId twice.
Inside the helpers for the count:
return this.upvoters.length
Also, inArray is a useful tool for checking if the value you have is inside an array.
if($.inArray(Meteor.userId(), this.upvoters)) //gives true if the current user's ID is inside the array
You will have to fetch the post and see if it contains the user's id in its downvoters array:
var post = Posts.findOne(postId);
if (post.downvoters && _.contains(post.downvoters, this.userId)) {
Posts.update({
_id: postId
},
{
$pull: {
downvoters: this.userId
},
$addToSet: {
upvoters: this.userId
},
$inc: {
downvotes: -1,
upvotes: 1
}
}
});
}