Meteor: collection find - mongodb

what is the best way to find collections in Meteor by ids?
I've tried this method:
UserCollection.findCollectionsByIds = function (ids) {
var collections = UserCollection.find({user: Meteor.userId(), _id: { $in: [ids]}});
return collections;
}
where:
ids = ['asgdajksdqa', 'ashudkjhaskc'] //an array of Object id
Now if I'm going to make a query like:
firstId = isd.pop();
var collections = UserCollection.find({_id: firstId });
it work correctly, so really I didn't understand what is wrong.
Thank you

Replace
UserCollection.find({user: Meteor.userId(), _id: { $in: [ids]}});
with
UserCollection.find({user: Meteor.userId(), _id: { $in: ids}});
Since ids is already an array ['asgdajksdqa', 'ashudkjhaskc'], if you wrap it in [...], you'll get [['asgdajksdqa', 'ashudkjhaskc']].

Related

mongo: update subdocument's array

I have the following schema:
{
_id: objectID('593f8c591aa95154cfebe612'),
name: 'test'
businesses: [
{
_id: objectID('5967bd5f1aa9515fd9cdc87f'),
likes: [objectID('595796811aa9514c862033a1'), objectID('593f8c591ba95154cfebe790')]
}
{
_id: objectID('59579ff91aa9514f600cbba6'),
likes: [objectID('693f8c554aa95154cfebe146'), objectID('193f8c591ba95154cfeber790')]
}
]
}
I need to update "businesses.likes" where businesses._id equal to a center value and where businesses.likes contains certain objectID.
If the objectID exists in the array, I want to remove it.
This is what I have tried and didn't work correctly, because $in is searching in all the subdocuments, instead of the only subdocument where businesses._id = with my value:
db.col.update(
{ businesses._id: objectID('5967bd5f1aa9515fd9cdc87f'), 'businesses.likes': {$in: [objectID('193f8c591ba95154cfeber790')]}},
{$pull: {'businesses.$.likes': objectID('193f8c591ba95154cfeber790')}}
)
Any ideas how how I can write the query? Keep in mind that businesses.likes from different businesses can have the same objectID's.

How to use $nin to exclude array of objects in Meteor, MongoDB, React

I want to exclude array of objects from my query when fetching Object.
mixins: [ReactMeteorData],
getMeteorData() {
// Standard stuff
var selector = {};
var handle = Meteor.subscribe('videos', selector);
var data = {};
// Return data = OK!
data.video = Videos.findOne({ _id: this.props._id });
// Fetch objects with $lte _id to exclude, Return id_ field array = OK!
data.excnext = Videos.find({ votes: data.video.votes, _id: {$lt: data.video._id}},{fields: {_id:1}},{sort: {_id: 1},limit:50}).fetch();
// Fetch objects by Votes, Exclude array of objects with $nin = NOT OK!
data.next = Videos.findOne({ _id: { $ne: this.props._id, $nin:data.excnext }, votes: { $gte: data.video.votes}},{ sort: { votes: 1, _id: 1 }});
return data;
},
Why is $nin not working like expected?
Am unsure if am doing something wrong when fetching my array or when returning it using $ini
Logged example = data.excnext
[ { _id: 'A57WgS6n3Luu23A4N' },
{ _id: 'JDarJMxPAnmeTwgK4' },
{ _id: 'DqaeqTfi8RyvPPTiD' },
{ _id: 'BN5qShBJzd6N7cRzh' },
{ _id: 'BSw2FAthNLjav5T4w' },
{ _id: 'Mic849spXA25EAWiP' } ]
Grinding on my first app using this stack. My core setup is Meteor,Flow-router-ssr, React-layout, MongoDB, React. What am trying to do is to fetch next object by votes, problem is that sometimes several objects have the same amount of votes, so then i need to sort it by id and exclude unwanted objects.
First of all am seeking the answer how to use $nin correct in my example above
Second, Suggestions / examples how to do this better are welcome, There could be a much better and simpler way to do this, Information is not easy to find and without any previous experience there is a chance that am complicating this more than needed.
// ❤ peace
In this case $nin needs an array of id strings, not an array of objects which have an _id field. Give this a try:
data.excnext = _.pluck(Videos.find(...).fetch(), '_id');
That uses pluck to extract an array of ids which you can then use in your subsequent call to findOne.

Mongoose Update Instance from Nested Array

In Mongoose, lets say I have a User object pulled from MongoDB and that user has an array of Interests. Now I get an instance of one of that user's Interests.
var user = ...
var interest = ...
... //Make some changes to interest.
How do I update that Interest object (after making some changes to it) within the User array in the DB?
Edit
Here is my current code. It doesn't work and doesn't give an error.
User.update(
{
'_id': user._id,
'interests._id': interest._id
},
{
'$set': {
'interests.$.xyzProperty': interest.xyzProperty
}
},
function(err,obj){//some error checking}
);
If you set an if for each interest, you can access the interest by the $ operator.
user document
{
_id: ObectId('54b568531ef35a7c348f21f2'),
interests: [
{
_id: 12345,
title: 'Tacos',
description: 'I Love tacos'
},
{...},
{...},
]
}
If I know which interest sub document I want to update, I simply query it like so:
UserModel.find({_id: ObectId('54b568531ef35a7c348f21f2'), 'interests.i_d': 12345}).lean().exec(function (err, user) {
var interest = ... //find specific interest
interest.description = 'I love tacos... Like, a lot'.
UserModel.update(
{
_id: user._id,
'interests._id': interest._id
},
{
$set: {
'interests.$.description': interest.description
}
},
function (err, update) {
console.log(err, update);
}
);
});
This uses the $ positional operator and updates the specific sub document(or item in an array).

Meteor publish: secret field of subdocument

I have the following collection with an array of subdocument:
{
_id:
players: [
{
_id: 1
answer
score:
},
{
_id: 2
answer:
score:
}]
}
I want to perform a publish function in order that it excludes the field answer of the other player. I.e player 1 should have on his local minimongo this doc:
{
_id:
players: [
{
_id: 1
answer
score:
},
{
_id: 2
score:
}]
}
I tried something like this:
Meteor.publish('game', function (id) {
return Game.find({_id: id}, {players.player_id: 0});
});
But I don't know how to only remove the field answer for the specific player.
I hate working with arrays like this in MongoDB. Personally I would use another collection GamePlayers with a document for each player in each game e.g.
Game ({ _id: g1 })
GamePlayers ({ _id: 0, gameId: g1, playerId: p1, answer: x, score: 0 });
GamePlayers ({ _id: 1, gameId: g1, playerId: p2, answer: y, score: 5 });
This would make things a lot easier.
But to actually answer your question here is a way to do it. I'm sure there is a more elegant way to do it but again I struggle using arrays in MongoDB so I can't think of it.
Since meteor publishes are effectively observeChanges functions we can do this:
note: this assumes that the _id of each player in the players array is equal to the user's Meteor.userId(), if it's not then you will need to provide the playerId as another argument to the publish along with gameId and change as appropriate.
I also assume your Games collection is called "games"
Games = new Meteor.Collection("games")
Meteor.publish('game', function(gameId) {
var self = this;
var handle = Games.find(gameId).observeChanges({
added: function(id, fields) {
self.added("games", id, removeSecretPlayerInfo(fields, self.userId));
},
changed: function(id, fields) {
self.changed("games", id, removeSecretPlayerInfo(fields, self.userId));
},
removed: function(id) {
self.removed("games", id);
}
});
self.ready();
self.onStop(function() {
handle.stop();
});
});
//this function takes all the fields that would be sent to the client,
//goes through the player array and if the player's id _id is not equal to
//the id of the user making the subscription we remove the answer from the array
//before sending it to them
var removeSecretPlayerInfo = function(fields, playerId) {
if (fields.players) {
for (var i = 0; i < fields.players.length; i++) {
if (fields.players[i]._id !== playerId)
delete fields.players[i].answer;
}
}
return fields;
}
You need to use quotations when querying a subfield. Also note that the second parameter to find is on options object that should have a property fields.
return Game.find({_id: id}, {fields: {'players.answer': 0}});

Resolving a ref inside of a MongoDB aggregate

I have a Product model object that has the following field in its schema:
category : { type: ObjectId, turnOn: false, ref: "category" }
It references a category model that has a title field in it:
var categorySchema = Schema({
title : { type: String }
});
I'm using the product.category property (which is of type ObjectId as shown above) in a MongoDB aggregate but really want the category.title property from the category model rather than _id in the final resultset.
The following code gets the job done, but you'll see that I'm having to do some looping at the end to "resolve" the title field for the given product.category (ObjectId). Is there anyway to do all of that within the aggregate? In other words, is there a way to get the category model object's title field in the groups that are returned rather than having to do the extra looping work? Based on posts I've researched I don't see a built-in way but wanted to double-check.
getProductsGroupedByCategory = function(callback) {
Category.find(function(err, cats) {
var aggregate = [
{
$group: {
_id: "$category",
products: {
$push: {
title: "$title",
authors: "$authors",
publishDate: "$publishDate",
description: "$description"
}
}
}
},
{
$sort: {
"_id": 1
}
}
];
Product.aggregate(aggregate, function(err, catProducts) {
//Grab name of category and associate with each group
//since we only have the category_id at this point
for (var i = 0; i<catProducts.length;i++) {
var catProduct = catProducts[i];
for (var j=0;j<cats.length;j++) {
if (catProduct._id.toString() === cats[j]._id.toString()) {
catProduct.category = cats[j].title;
}
}
};
callback(err, catProducts);
});
});
}, //more code follows
An example datum would be helpful along with what you need out of it. From What I understand you are looking to get the title in to the grouping criteria and that should be doing by having a compound grouping criteria i.e.
_id: {category: "$category", title: "$title"}
If the title is within an array, you should do unwind, group and then wind again to achieve the result.