I've noticed that wherever I have a publication definition involving $ne or $nin, it has no effect. For example, I define a publication as
Meteor.publish('testing', function() {
return Courses.find({name: {$ne: 'Course A'}})
});
I have made sure that I have a course with name "Course A", however, when I subscribe like this on the client:
MeteorObservable.subscribe("testing").subscribe(() => {
console.log(Courses.find().fetch())
});
I get every single course in the database (including the one with name "Course A"). In case it's relevant, my definition for Courses is: export const Courses = new MongoObservable.Collection<Course>('courses');.
Is my selector wrong, or is it a bug with Meteor? When I run the same selector on the client side, everything works as expected.
Did u check if you disabled/remove autopublish package? You can check it inside .meteor/packages file. If yes, then remove it so meteor respect your publications.
Let me know if this solves your problem. Thanks!
Update 1:
Try this:
MeteorObservable.subscribe("testing").subscribe(() => {
console.log(Courses.find({name: {$ne: 'Course A'}}).fetch());
});
Related
I am working on a query that need to update a subdocument in meteor mongo. My code looks like this:
Cases.update(
{"_id":doc._id,"notes._id": doc.noteid},
{$set:{
'notes.$': {
'note': doc.note,
'updatedBy': currentUser,
'updatedAt': date
}
}});
this does work, however it does remove other fields that are not in the update such as "createdAt" and "date". I went as far as doing this but i get the same result:
Cases.update(
{"_id":doc._id,"notes._id": doc.noteid},
{$set:{
'notes.$': {
'note': doc.note,
'updatedBy': currentUser,
'updatedAt': date,
'createdBy':doc.createdBy,
'date': doc.date,
'_id':doc.noteid
}
}});
the notes.$._id, date and createdBy fields are removed in the opertion. I am using aldeed simple schema and collection 2 as packages of the autoForm package. This update is however been done using a generic form with a Meteor.call. I am using meteor 1.2.1. I know that collection 2 has the removeEmptyString setting turned on by default that is why I tried doing it the second way but it still does not work. Can some one please help?
Your $set is saying, "Assign the notes.$ object to this object I'm giving you, and delete whatever is currently there."
You want to do something like:
Cases.update( {"_id":doc._id, "notes._id": doc.noteid},
{
$set:{
'notes.$.note': doc.note,
'notes.$.updatedBy': currentUser,
'notes.$.updatedAt': date
}
});
My $set is saying, "Assign these three particular fields of the notes.$ object to the values I'm giving you, and don't touch anything else."
I want to make a publication with several additional fields, but I don't want to either use Collection.aggregate and lose my publication updates when the collection change (so I can't just use self.added in it either).
I plan to use Cursor.observeChanges in order to achieve that. I have two major constraints:
I don't want to publish all the documents fields
I want to use some of the unpublished fields to create new ones. For example, I have a field item where I store an array of item _id. I don't want to publish it, but I want to publish a item_count field with the length of my field array
Here comes the approach:
I plan to chain find queries. I never did that so I wonder if it possible. The general (simplified) query structure would be like this: http://jsfiddle.net/Billybobbonnet/1cgrqouj/ (I cant get the code properly displayed here)
Based on the count example in Meteor documentation, I store my query in a variable handle in order to stop the changes notification if a client unsubscribes:
self.onStop(function () {
handle.stop();
});
I add a flag initializing = true; before my query and I set it to true just before calling self.ready();. I use this flag to change my itemCount variable only if it is the publication is initialized. So basically, I change my switch like that:
switch (field) {
case "item"
if (!initializing)
itemCount = raw_document.item.length;
break;
default:
}
I wanted to check that this approach is good and possible before committing into big changes in my code. Can someone confirm me if this is the right way to go?
It's relatively easy to keep fields private even if they are part of the database query. The last argument to self.added is the object being passed to the client, so you can strip/modify/delete fields you are sending to the client.
Here's a modified version of your fiddle. This should do what you are asking for. (To be honest I'm not sure why you had anything chained after the observeChanges function in your fiddle, so maybe I'm misunderstanding you, but looking at the rest of your question this should be it. Sorry if I got it wrong.)
var self = this;
// Modify the document we are sending to the client.
function filter(doc) {
var length = doc.item.length;
// White list the fields you want to publish.
var docToPublish = _.pick(doc, [
'someOtherField'
]);
// Add your custom fields.
docToPublish.itemLength = length;
return docToPublish;
}
var handle = myCollection.find({}, {fields: {item:1, someOtherField:1}})
// Use observe since it gives us the the old and new document when something is changing.
// If this becomes a performance issue then consider using observeChanges,
// but its usually a lot simpler to use observe in cases like this.
.observe({
added: function(doc) {
self.added("myCollection", doc._id, filter(doc));
},
changed: function(newDocument, oldDocument)
// When the item count is changing, send update to client.
if (newDocument.item.length !== oldDocument.item.length)
self.changed("myCollection", newDocument._id, filter(newDocument));
},
removed: function(doc) {
self.removed("myCollection", doc._id);
});
self.ready();
self.onStop(function () {
handle.stop();
});
To solve your first problem, you need to tell MongoDB what fields it should return in the cursor. Leave out the fields you don't want:
MyCollection.find({}, {fields: {'a_field':1}});
Solving your second problem is also pretty easy, I would suggest using the collection helpers packages. You could accomplish this easily, like so:
// Add calculated fields to MyCollection.
MyCollection.helpers({
item_count: function() {
return this.items.length;
}
});
This will be run before an object is added to a cursor, and will create properties on the returned objects that are calculated dynamically, not stored in MongoDB.
In my meteor app, I want to publish a chatmate according to the chat object's members: basically there are two members, the one that is not the current user is the one I want to publish. Here's the code. (members is a list which always contains two different user ids)
Meteor.publish('chatmate', function(chat_id) {
var chat = Chats.findOne({_id:chat_id, members: this.userId});
var chatmate = undefined; // just in case... didn't know any better
if (chat) {
for (var i = 0; i < 2; i++) {
if (chat.members[i] !== this.userId)
chatmate = Meteor.users.find(chat.members[i], {fields: {'profile.name': 1}});
}
}
return chatmate;
});
(PS: yes, my publication is in the server folder)
My problem is: my first line of code returns undefined. But if I go on mongo and type db.chats.findOne(ObjectId('<mychatsid>')), I do get my record in the output, along with its members. Problem is, it seems I cannot use this useful ObjectId() method in Meteor!
What am I doing wrong here?
Did you insert these items directly into the mongo shell, or else mongorestore them from another database? By default, Meteor uses strings for _ids (although this can be changed by settings the idGeneration option to "MONGO" when the Collection is declared, as discussed here), whilst stand-alone MongoDB uses ObjectIds, which is what you've got here.
To cut a long story short though, you need to create a new ObjectID object and search based on that if this is the format your _ids are in:
Chats.findOne({ _id: new Meteor.Collection.ObjectID(chat_id), members: this.userId });
I need to select users for corresponding data from query.
I have this collection in my DB (two or more rows are output of my query as well)
> db.Friends.find()
{ "userId" : "k3XCWdN5M2pbzBiFD", "followeeId" : "3MTmHcJNEzaaS8hrd","_id" : "aiRD.." }
{ "userId" : "k3XCWdN5M2pbzBiFD", "followeeId" : "SoTozuZ4nWooRBeFz","_id" : "QingX.." }
When it would be just one result as findOne(...) the second query would looks like this:
users.findOne({ _id: firstQueryResult.followeeId })
But now the problem is... how can i select the users from users collection when i dont have only one followeeId but more of them?
Please someone show me an example of code.
My research:
Is this a good solution?
friendsData.forEach(function(relationShip) {
followeeIds.push(relationShip.followeeId);
});
console.log(followeeIds);
Ok i finalllly figure out the problem.For next readers:
Check if autopublish is enabled or disabled.
If is disabled you need to publish the collection from the DB
Meteor.publish("userData", function () {
return Meteor.users.find({},
{fields: {'username': 1}});
});
PS: i want to publish only username field and thats all!
You need to subscribe the data as well!
Meteor.subscribe("userData");
Now you can access other users data this way:
users= Meteor.users.findOne({username: "Nolifer"});
To my original problem ... i will probably use this function for iterate over more then one row result(its more a SQL term but i am not sure what term use in mongoDb maybe a document? whatever):
users.forEach(function(user) {
console.log(user);
});
Thats it!
P.S.: I think there is nothing wrong on this but what i know right? :) So if someone know a better way please leave a comment. If not give me know if it was useful for you :)
According to the mongo manual, use the $in operand: http://docs.mongodb.org/manual/reference/operator/in/#op._S_in
db.inventory.find( { qty: { $in: [ 5, 15 ] } } )
I've just started to look at meteor and I'm stuck trying to update a record within an array within a record. Say i have a document that looks something like this:
Users:
{
_id: "somerandom",
name: "name1",
items, [
{
name: "item1",
data: "somedata",
...
},
{
name: "item2",
data: "somedata",
...
}
],
...
},
...
And I want to update the data of items 'item1'. I can't find anything on how to do this in meteor, but from what I have read about MongoDB I think that the correct way would be something like
Users.update({_id: userId, "items.name": 'item1}, {$set: {"items.$.data": newData}});
but since the MongoDB used in Meteor doesn't support $ it won't work, on the other hand I might be way of how this should be done.
Does anyone have a solution for this?
Use Meteor.methods() and implement your database operation on the server side and call it using Meteor.call() from the client. This feature is not yet implemented in Meteor and it is documented here.
You can read more in the discussion on this issue raised on Github, here.
I found a workaround at meteor's github https://github.com/meteor/meteor/blob/master/examples/parties/model.js
The idea is to first get the index of the array-item you want to change and then use that index instead of $. So in this case it would be something like
user = Users.findOne(userId);
index = _.indexOf(_.pluck(user.items, 'name'), 'item1');
modifier = {$set: {}};
modifier.$set["items." + index + ".data"] = newData;
Users.update(userId, modifier);