0

Being new to Meteor JS, I'm confused on how to update a record. I have 2 templates AddSchoolLayout and Schoolcontactlayout, AddSchoollayout creates the record in Mongo db, now, for the same school I want to add its address still on the same DB NewSchoolDB but as I tried this I keep getting the error below about wrong ID. What wrong am I to right?

Note that my language might not correlate with Mongo's; I'm still fresh, coming from the SQL background.

This is the method.js where the record is been saved.

//methods.js
    if (Meteor.isServer) {
        Meteor.methods({
            SchoolRegister: function (phone, schoolemail) {
                if (!Meteor.userId()) {
                    throw new Meteor.error('Not authorized');
                    return false;
                }else{

                    NewSchoolDB.insert({
                        authorId: Meteor.userId(),
                        phone: phone,
                        schoolemail
                    });
                }
            }
        });
    }

This is the event for saving a new school

//add school
Template.AddSchoolLayout.events({
    'submit .addnewschool': function (event, template) {
        event.preventDefault();

        var newschoolname = trimInput(event.target.newschoolname.value);

        if (isNotEmpty(newschoolname)) {

            Meteor.call('SchoolRegister', newschoolname,
                function (error, response) {
                    if (error) {
                        Bert.alert(error.reason, 'danger', 'growl-top-right');
                        return false;
                    }else{
                        Bert.alert("School successfully created", "success", "growl-top-right");
                        FlowRouter.redirect('/schoolcontact');
                    }
                });

        }
        return false;
    }
});

This is where I want to update the school address

//school contact
Template.SchoolContactLayout.events({
    'submit .contactschool': function (event) {
        event.preventDefault();

        var phone = trimInput(event.target.phone.value);    
        if (isNotEmpty(phone)) {
            Meteor.call('SchoolRegister', phone, function (error, response) {
                if (error) {
                    Bert.alert(error.reason, 'danger', 'growl-top-right');
                    return false;
                }else{
                    Bert.alert('School address updated successfully', 'success', 'growl-top-right');
                    FlowRouter.redirect('/logo-upload');
                }
            });
        }
        return false;
    }
});

Error logged on the console

I20170524-17:44:14.051(1)?     at packages/ddp-server/livedata_server.js:559:43
I20170524-17:51:54.678(1)? Exception from sub NewSchoolDB id onFTu2j3xRmbqC5WF TypeError: this.userId is not a function
I20170524-17:51:54.710(1)?     at [object Object]._handler (lib/pulbish/published.js:3:13)
I20170524-17:51:54.712(1)?     at maybeAuditArgumentChecks (packages/ddp-server/livedata_server.js:1737:12)
I20170524-17:51:54.713(1)?     at [object Object]._.extend._runHandler (packages/ddp-server/livedata_server.js:1035:17)
I20170524-17:51:54.714(1)?     at [object Object]._.extend._startSubscription (packages/ddp-server/livedata_server.js:853:9)
I20170524-17:51:54.715(1)?     at [object Object]._.extend.protocol_handlers.sub (packages/ddp-server/livedata_server.js:625:12)
I20170524-17:51:54.719(1)?     at packages/ddp-server/livedata_server.js:559:43
halfer
  • 19,824
  • 17
  • 99
  • 186
ken4ward
  • 2,246
  • 5
  • 49
  • 89
  • I think your problem is with the use of Meteor.userID in what is essentially the server context. That can create problems, read : https://guide.meteor.com/accounts.html#current-user – mstorkson May 24 '17 at 21:02

1 Answers1

1

Your SchoolRegister method accepts 2 arguments: phone and schoolmail. When you create the school you call the methods with one argument called newschoolname. So something is wrong here with your naming convention, but it shouldn't really matter regarding your question.

With MongoDB, you use insert to add a new record to your collection. If you need to update it, use update. So one way to solve your problem is to:

  • In AddSchoolLayout, call your method to insert the document the first time. NewSchoolDB.insert(...) will return the ID of the created record. Keep that ID and pass it to your next page, for exemple in the URL.
  • In your next page, SchoolContactLayout, you need to call a new method which is going to update your school, using the ID returned by the previous method. This new method will look something like this:

    SchoolUpdate: function (schoolId, phone) {
        if (!Meteor.userId()) {
            throw new Meteor.error('Not authorized');
            return false;
        }else{
            NewSchoolDB.update(schoolId, { $set: { phone } });
        }
    }
    

The first argument of the update MongoDB function is the ID of the record you want to update. The second arguments are the modifiers you want to use to update your record. Here is the full list of modifier you can use: update modifiers

EDIT: how to pass ID from one layout to another:

I didn't use FlowRouter for a while and I can't test it right now so you may have to do some correction, but here is how I would do it to give you an idea:

First you need to define your route SchoolContactLayout with something like this:

FlowRouter.route('/schoolcontact/:schoolId', {
  name: 'schoolContact',
});

This adds a schoolId parameter to the route.

In your SchoolRegister method, get the return ID and return it:

var id = NewSchoolDB.insert({
  authorId: Meteor.userId(),
  schooleName
});
return { id }

Edit your redirection FlowRouter.redirect('/schoolcontact'); with FlowRouter.go('/schoolcontact/' + response.id);

You can then edit your contactSchool event with something like this:

Template.SchoolContactLayout.events({
  'submit .contactschool': function (event) {
     event.preventDefault();

     var schoolId = FlowRouter.getParam('schoolId');
     var phone = trimInput(event.target.phone.value);    
     if (isNotEmpty(phone)) {
       Meteor.call('SchoolUpdate', schoolId ,phone, function (error, response) {
         if (error) {
           Bert.alert(error.reason, 'danger', 'growl-top-right');
           return false;
         }else{
           Bert.alert('School address updated successfully', 'success', 
            'growl-top-right');
           FlowRouter.redirect('/logo-upload');
         }
       });
     }
     return false;
   }
 });

Notice the var schoolId = FlowRouter.getParam('schoolId'); to get the ID from URL parameter so I can use it in the update method.

Damien Monni
  • 1,418
  • 3
  • 15
  • 25
  • Thanks. This is in the right direction, my next question is how do I pass in the ID. Should it be in a session? – ken4ward May 24 '17 at 19:56
  • Thank you very much. I used session to get the id since it's a global variable and retrieved. It worked. Any side-effect of this? – ken4ward May 25 '17 at 09:52
  • 1
    It is often considered better if you can as much as possible use scopped variable instead of global variable, so you get more "control" over it. With session you need to manage the variable a bit more (set it, remove it, replace it) and because it is global you are not always really sure about what value really is inside. But in your case it should work without too much problem. Global variables tends to be a problem with large project. :) – Damien Monni May 25 '17 at 11:48
  • 1
    Thank you very much for this great professional insight. I'll keep you posted as things goes and the application scales. – ken4ward May 25 '17 at 11:55
  • Is there any way I can get values using a where clause in Meteor/MongoDB. I just want to use the id to return the saved document. An example ```return NewSchoolDB.findOne({where id = "doc_id"})```? – ken4ward May 25 '17 at 11:59
  • 1
    Let's say the doc ID is a variable called docId, then it is as simple as `return NewSchoolDB.findOne({_id: docId});`. [Here is the doc](https://docs.mongodb.com/manual/tutorial/query-documents/#specify-equality-condition). Just notice every record has an ID called _id and not id. – Damien Monni May 25 '17 at 12:03
  • Thanks. Was able to reproduce this on the console. Worked perfectly. What if i want to select only a few docs from it. Lets say it has 10 variables: ```var1, var2, var3, ...., ..., ... ``` If I only want to get var4 and var7, how do i do that? – ken4ward May 25 '17 at 12:14
  • `return NewSchoolDB.findOne({_id: docId}, { fields: { var4: 1, var7: 1 } });`. – Damien Monni May 25 '17 at 12:20
  • Reading the mongo doc, it seems you can even remove the fields attribute: ` return NewSchoolDB.findOne({_id: docId}, { var4: 1, var7: 1 } );` I didn't test it, you can try. ;) – Damien Monni May 25 '17 at 12:21