I want to test a few things that regards some data I have stored stored in a collection called exams. This is my code
Template.Examinations.events({
'click .reactive-table tr': function() {
Session.set('selectedPersonId', this._id);
var cursor = Exam.findOne(Session.get("selectedPersonId"));
if (!cursor.count()) return;
cursor.forEach(function(doc){
console.log(doc._id);
});
},
});
Every time I run the code by clicking a row, I get the error
Uncaught TypeError: cursor.count is not a function
Why am I getting this error?
Update
{
"_id" : "RLvWTcsrbRXJeTqdB",
"examschoolid" : "5FF2JRddZdtTHuwkx",
"examsubjects" : [
{
"subject" : "Z4eLrwGwqG4pw4HKX"
},
{
"subject" : "fFcWby8ArpboizcT9"
}
],
"examay" : "NrsP4srFGfkc5cJkz",
"examterm" : "5A5dNTgAkdRr5j53j",
"examclass" : "gYF2wE4wBCRy9a3ZC",
"examname" : "First",
"examdate" : ISODate("2016-05-07T22:41:00Z"),
"examresultsstatus" : "notreleased"
}
You are using Exam.findOne which will return an object but not array, which is causing the error cursor.count is not a function. You should use Exam.find({}).fetch() and then you can get the count form the result.
Template.Examinations.events({
'click .reactive-table tr': function() {
Session.set('selectedPersonId', this._id);
var examsArray = Exam.find({ personId: this._id}).fetch();
examsArray.forEach(function(doc){
console.log(doc._id);
});
},
});
Related
this is my colletion:
{
"_id" : "Kan6btPXwNiF84j8e",
"title" : "Chapter Title 1",
"businessId" : "qmWJ3HtZrpka8dpbM",
"createdBy" : "GfdPfoPTiSwLv8TBR",
"sections" : [
{
"id" : "T5KAfTcCb7pCudT3a",
"type" : "TEXT",
"data" : {
"text" : "<h1>2</h1><h1>asd</h1>"
},
"createdAt" : ISODate("2016-12-03T10:35:59.023Z"),
"updatedAt" : ISODate("2016-12-03T10:35:59.023Z")
}
],
"createdAt" : ISODate("2016-12-02T12:15:16.577Z"),
"updatedAt" : ISODate("2016-12-03T12:54:50.591Z")
}
this is the meteor method I am calling from client side
deleteSection: function (section_id, chapter_id) {
chaptersCollection.update(
{$and: [{_id: chapter_id}, {'sections.id': section_id}]},
{$pull: {'sections': {'id': section_id}}},
function (err, numAffected) {
if (err) {
console.log(err);
return err;
}else{
console.log(numAffected);
}
});
return 'Section Successfully Deleted';
}
in callback function of meteor method, it returns 1 as affected rows. But on server document is not updating.
Any suggestion where am I wrong?
Do you really need $and?
deleteSection: function (section_id, chapter_id) {
chaptersCollection.update(
{_id: chapter_id, 'sections.id': section_id},
{$pull: {'sections': {'id': section_id}}},
function (err) {
if (err) {
console.log(err);
return err;
}else{
console.log('success');
return 'success';
}
});
}
I had a similar issue when I tried to use pull in a project. So instead of using $pull, I handled the array outside of the database and then set the array as the one I handled outside. So maybe you can try something like that as an alternative way
deleteSection: function (section_id, chapter_id){
const oldArray = chaptersCollection.findOne(chapter_id).sections;
const newArray = oldArray.filter(function(section) {
return section.id !== section_id
});
chaptersCollection.update({_id: chapter_id},
{$set: {sections: newArray}},
function (err, numAffected) {
if (err) {
console.log(err);
return err;
}else{
console.log(numAffected);
}
});
return 'Section Successfully Deleted';
}
I have the following route :
this.route('groupPage', {
path: '/group/:_groupId',
waitOn: function(){
return Meteor.subscribe("groupPage", this.params._groupId);
},
data: function() {
var group = Groups.findOne({_id: this.params._groupId});
var members = Meteor.users.find({_id : {$in: group.memberIds}}); ******** ISSUE HERE******
return {
group: group,
members: members,
}; }});
and the following publication :
Meteor.publishComposite('groupPage', function(groupId, sortOrder, limit) {
return {
// return the group
find: function() {
if(this.userId){
var selector = {_id: groupId};
var options = {limit: 1};
return Groups.find(selector, options);
}
else{
return ;
}
},
children: [
{ // return the members
find: function(group) {
var selector = {_id: {$in: group.memberIds} };
return Meteor.users.find(selector);
}
}
]}}) ;
Now my issue is that : when the related page renders for the first there is no problems but when i actualize the group Page view the line : var members = Meteor.users.find({_id : {$in: group.memberIds}}); gives me the error : undefined object don't have memberIds property. i guess it's because the subscription is not yet ready when doing group.memberIds , isn't it ? Please a hint.
Thanks.
The data function doesn't wait for the subscription to be ready. Further more, subscriptions in the router are considered an anti-pattern for the most part, and should be done in the template: https://www.discovermeteor.com/blog/template-level-subscriptions/
I would pass to the template the groupId, and then get the group and members in the template, like so:
this.route('groupPage', {
path: '/group/:_groupId',
data: function() {
return {
_groupId: this.params._groupId,
}
}
});
and then in the template file:
Template.groupPage.onCreated(function(){
this.subscribe("groupPage", this.data._groupId);
})
Template.groupPage.helpers({
members(function(){
tempInst = Template.instance()
var group = Groups.findOne({_id: tempInst.data._groupId});
return Meteor.users.find({_id : {$in: group.memberIds}});
})
})
The general pattern of your route and publication are all solid. I suspect it's something simple such as:
There is no group with the _id you're using
You're not logged in when you load the route
Here's a version of your code that guards against the error. Note that the publication executes this.ready() instead of just returning if the user is not logged in.
this.route('groupPage', {
path: '/group/:_groupId',
waitOn: function(){
return Meteor.subscribe("groupPage", this.params._groupId);
},
data: function() {
var group = Groups.findOne({_id: this.params._groupId});
var members = group && Meteor.users.find({_id : {$in: group.memberIds}});
return { group: group, members: members };
}
});
Meteor.publishComposite('groupPage', function(groupId,sortOrder,limit) {
return {
find: function() {
if (this.userId) return Groups.find(groupId);
this.ready()
}
},
children: [
find: function(group) {
var selector = {_id: {$in: group.memberIds} };
return Meteor.users.find(selector);
}
]
});
In my Meteor app, I have a simple array field called relatedSentences. It is defined using SimpleSchema
relatedSentences: {
type: [String],
label: "Related Sentence",
optional: false,
defaultValue: []
},
It's data can be seen in the Mongo console:
"_id" : "ei96FFfFdmhPXxRWb",
"sentence" : "the newest one",
"relatedSentences" : [
"Ls6EyBkbcotcyfLyw",
"6HKQroCjZhG9YCuBt"
],
"createdAt" : ISODate("2015-10-25T11:21:25.338Z"),
"updatedAt" : ISODate("2015-10-25T11:41:39.691Z")
But when I try to access this field using this, it is returned as a raw string.
Template.showSentence.helpers({
translations: function() {
console.log("related: " + this.relatedSentences);
Meteor.subscribe('sentences', function() {
var relatedSentences = Sentences.find({_id: {$in: this.relatedSentences} }).fetch();
console.log("rel count" + relatedSentences.length);
return relatedSentences;
});
}
});
In the console I get an error. See the return value from the this.relatedSentences. It is the contents of the array as a string, with a comma interpolated.
related: Ls6EyBkbcotcyfLyw,6HKQroCjZhG9YCuBt
selector.js:595 Uncaught Error: $in needs an array
Not sure what is going on here.
Some Progress
I have made some progress, but not yet at a solution. By adding blackbox: true to the SimpleSchema definition, what looks like an array is now returned... but alas it is still failing. See below.
relatedSentences: {
type: [String],
label: "Related Sentence",
optional: false,
blackbox: true,
defaultValue: []
},
Now I get the results below in the console. The values are now being returned as a quoted array, which is what I expected. But the $in is still not seeing it as an array.
["Ls6EyBkbcotcyfLyw", "6HKQroCjZhG9YCuBt"]
selector.js:595 Uncaught Error: $in needs an array
How did the data get populated
In answer to #Kyll - this is how the data was originally populated. I am using AutoForm,
{{> afQuickField name='relatedSentences.0' value=this._id type="hidden"}}
but then adding the array data via a hook.
AutoForm.addHooks('translateForm', {
onSuccess: function (operation, result, template) {
Meteor.subscribe('sentences', function() {
var translatedSentence = Sentences.findOne(result);
var originalSentenceId = translatedSentence.relatedSentences[0]
Sentences.update(
{ _id: originalSentenceId},
{ $push: { relatedSentences: result}
});
Router.go('showSentence',{ _id: originalSentenceId } );
});
}
});
The problem here is the scope of this. You are referring to it inside the subscribe function, where this has a different context. Set a varibale to this in the context where it works, then use that variable instead:
Template.showSentence.helpers({
translations: function() {
console.log("related: " + this.relatedSentences);
var this_related_sentences = this.relatedSentences;
Meteor.subscribe('sentences', function() {
var relatedSentences = Sentences.find({_id: {$in: this_related_sentences} }).fetch();
console.log("rel count" + relatedSentences.length);
return relatedSentences;
});
}
});
My doc strucure:
"_id" : "p5NXQZd5b5dbMrECW",
"feed_id":"xfsfasfsadfdfafs",
"comments" : [
{
"user" : "fzkhiAArD4mgAAjbL",
"comment" : "First comment",
"commentedAt" : 1422416042795
},
{
"user" : "fzkhiAArD4mgAAjbL",
"comment" : " second comment",
"commentedAt" : 1422416071633
},
{
"user" : "fzkhiAArD4mgAAjbL",
"comment" : " third comment is so longgggggggggggggggggggggggggggggggggggg",
"commentedAt" : 1422416087707
},
.......
....
}
my code,Initially I'm sending 3 comments to the user using publish-composite
Meteor.publishComposite('hub_feed',function(hubid){
return {
find: function() {
return HubFeeds.find({hub_id:hubid});
},
children: [
{
find: function(feed) {
var res=FeedHits.findOne({feed_id:feed._id});
if(res){
if(_.has(res,"comments")){
return FeedHits.find({_id:res._id},{fields: {comments:{$slice: -3}}});
}
}
}
}
]
}
});
I'm subscribing in the client
Meteor.subscribe("hub_feed")
which is working fine and I displayed the 3 comments.
Now on click event I want to load more comments,so created another publish function
Meteor.publish("getExtraFeedComments",function(noOfComments,feedid){
var required=noOfComments+10;
..........
return FeedHits.find({feed_id:feedid},{fields: {comments:{$slice: -required}}});
});
I'm subscribing to this publish function,when user clicks on load more comments button
'click #loadMoreComments':function(){
var hasComments=FeedHits.findOne({feed_id:this._id});
if(hasComments && _.has(hasComments,"comments")){
var noOfComments=hasComments.comments.length;
var handle=Meteor.subscribe("getExtraFeedComments",noOfComments,this._id);
if(handle.ready()){
console.log('ready');
console.log(FeedHits.find().fetch());
}
}
}
Here is my issue, In console I'm not getting ready and also I'm getting only 3 comments.
why is this subscribe onclick event is not working.
Nte:In server before publishing I've checked the results .
It is displaying 5 comments,but in client it is showing only 3 comments
...........
......
console.log(FeedHits.find({feed_id:feedid},{fields: {comments:{$slice: -required}}}).fetch())
return FeedHits.find({feed_id:feedid},{fields: {comments:{$slice: -required}}});
Edit
with callback function
Meteor.subscribe("getExtraFeedComments",noOfComments,this._id,function(){
console.log(FeedHits.findOne({feed_id:self._id}));
});
I'm getting 3 values only I'm not getting more values
It looks like you are trying to do a synchronous call from the client:
var handle=Meteor.subscribe("getExtraFeedComments",noOfComments,this._id);
In Meteor the client is never synchronous, so in this case 'handle' will not return what you expect. It probably will be null.
In order to accomplish what you are trying to do, you need a callback in your subscribe function.
Meteor.subscribe("getExtraFeedComments", function(){ /* sub ready here */})
Hope that helps.
The problem I'm facing is that my userId function is running before Meteor.user() is ready, therefore there is no Meteor.user()._id present and thus I get Exception in defer callback: TypeError: Cannot read property '_id' of undefined when I run the code. If I use the command Meteor.userId(), it fixes it for that part, but it doesn't solve the big issue being that Meteor.user() isn't ready.
Here's my code:
userId : function(){
console.log('userId called and here is the Meteor.user(): ', Meteor.user());
return (this.params._id || Meteor.user()._id);
},
waitOn: function () {
console.log('waitOn called');
return Meteor.subscribe('userProfile', this.userId())
},
addedData : function(){
........
},
data: function(){
...........
},
onBeforeAction : function(){
............
},
onStop : function(){
_.each(this.subscriptions, function(sub){
sub.stop();
});
}
How do I fix this?