Want to get value as result from server side and got an internal server error 500

I’m getting error internal server error and not getting a result that is returned from server side with meteor methods.
I wonder why.

server side

Meteor.methods({
  'file.get'(uuid) {
    check(uuid, String);
    const file =
     Collection1.find({_id: uuid}) || Collection2.find({_id: uuid});
     console.log('file', file); // cursor {...} 
    return file;
  },
});

client side

  Meteor.call('file.get', uuid, (error, result) => {
    console.log('result', result);  // result  undefined
    console.log('error', error);  // error errorClass{...}  just saying internal server error 500
  });
  

Could I not access result which return from server side?

I don’t know if this matters but this Collection1 and Collection2, we store files data and these filed are stored in chucks.

There was no result because of the internal server error. You need to figure out and solve the internal server error first. Check your server console or logs for more details

2 Likes

Do add to @rjdavid your code will probably never reach the second condition searching in Collection2 because, if I am not wrong, collection.find always returns a cursor (and if you do fetch() you get an array/empty array). Collection.find() is always true. You can do findOne() which returns undefined if no document exists as per your query or Object if a document is found.

You can also return Collection.find({ condition }).fetch()?.[0] if you want this to be a correct true / false condition.

@paulishca @rjdavid Thank you for your answer!

I did Collection.findOne() first, but got undefined so I switched to Collection.find().

Also, I returned Collection.find... directly like this on the server side.

Meteor.methods({
  'file.get'([uuid]) {
    check(uuid, String);
    return Collection1.find({_id: uuid}).fetch()?.[0];
  },
});

But I’m still getting "Internal server error [500]" on the client side.

On the terminal, I’m seeing an error massage saying Exception from sub attachments id WCZyvMDxtDtHtkxwW Error: Publish function returned an array of non-Cursors

U got undefined because you should get undefined if there is no document and consequently you move on to your Collection2

Ok, can you check on your second argument of Meteor.call. I think it needs to be an object and you probably pass a string instead.

1 Like

My bad! I made some change so the current codes looks like this.

server side

Meteor.methods({
  'file.get'([uuid]) {  // changed uuid to [uuid]
    check(uuid, Match.OneOf(String, null, undefined));  // changed
    const file =
     Collection1.find({_id: uuid}) || Collection2.find({_id: uuid});
     console.log('file', file); // cursor {...} 
    return file;
  },
});

client side

  Meteor.call('file.get', [uuid], (error, result) => {  // changed uuid to [uuid]
    console.log('result - call', result);
    console.log('error - call', error);
  });

And you talking about console.log on meteor.call for uuid?

  Meteor.call('file.get', [uuid], (error, result) => {  // changed uuid to [uuid]
    console.log('uuid - call', uuid);  // 59xpMCRnE6oGAKd85
    console.log('result - call', result);
    console.log('error - call', error);
  });

Meteor.call(‘methodname’, { keyOne: ‘x’, keyTwo: [array], keyThree: {key: value} }). please check the manual.

I thought the arguments need to be array not object?

Meteor.call(name, [arg1, arg2…], [asyncCallback])

Meteor.call

but I tried to pass as an object like {_id:uuid} on meteor call and

Meteor.methods({
  'file.get'({uuid}) {
    check(uuid, Match.OneOf(String, null, undefined));
    console.log('uuid - methods', {uuid});  // uuid:undefined
    return UserFiles.find({_id: uuid}).fetch()?.[0];
  },
});

logged {uuid: undefined}

I think you could read here: Methods | Meteor Guide

In your last example, you key is _id not uuid.
Just some comments about methods.

  • You can use something called an optimistic UI. In this case, your method has to be defined on both Client and Server so that the Client performs a simulation of the result for a faster UI response.
  • The most secure way to run methods is to define them on the server and call them from the client.
    To define Server only, you can just put a methods.js file inside a “server” folder. All folders named as “server” are treated as server only files, everywhere in your project tree.
    If however you define it outside a “server” folder, you can include the entire method function within a conditions such as:
methodName: () => {
   If (Meteor.isServer) {
       ...method content here.
   }

}

  • Many of us use a library called ValidatedMethod in which case your method looks like:
import { Meteor } from 'meteor/meteor'
import { ValidatedMethod } from 'meteor/mdg:validated-method'
import SimpleSchema from 'simpl-schema'

new ValidatedMethod({
  name: 'file.get',
  validate: new SimpleSchema({
    _id: String, /* { type: String, optional: true } if _id is not a mandatory argument. */
  }).validator(),
  run ({ _id }) {
    if (Meteor.isServer) {
     console.log(_id)
      if (!this.userId) { throw new Meteor.Error('not-authorized') } // check a user is logged in if this is your case.
    
     let file =  Collection1.findOne(uuid)  // this is equivalent of Collection1.findOne({ _id: uuid }). If you only query for the _id, you can just skip the Object format.
      if (file) {
         return file
      }
     
     file =  Collection2.findOne(uuid)  // this will return undefined if no document with this id is found.
     return file
    }
  }
})


2 Likes

Thank you @paulishca

It seems like I got confused or didn’t write code correctly but now I don’t get the internal server error
So thank you very much!

But I’m getting Exception while simulating the effect of invoking 'file.get' TypeError: Cannot read properties of undefined (reading 'fetch')

server side

Meteor.methods({
  'file.get'(uuid) {
    check(uuid, Match.OneOf(String, null, undefined));
    returnCollection1.findOne({_id: uuid}).fetch();
  },
});

client side

  useEffect(() => {
    Meteor.call('attachments.get', uuid, (error, result) => {
      console.log('result - call', result);   // [{...}]  (there is an object)
      setAttachment(result); 
    });
  }, []);

So like the error message said, I removed fetch() on the server side.

Meteor.methods({
  'file.get'(uuid) {
    check(uuid, Match.OneOf(String, null, undefined));
    returnCollection1.findOne({_id: uuid});  // removed fetch()
  },
});

and then I don’t get any objects as a result, but not seeing the TypeError: Cannot read properties of undefined (reading 'fetch') message.

1 Like

One other thing I’m not clear about is when I need fetch() on the server side?

Meteor.methods({
  'file.get'(uuid) {
    check(uuid, String);
    return Collection1.findOne({_id: uuid});  // here
  },
});

I thought the return has to be like
return Collection1.findOne({_id: uuid}).fetch();
But again I’mgetting TypeError: Cannot read properties of undefined (reading 'fetch') message, so I don’t need fetch() all the time Or I do need fetch() if it’s Collection1.find() ?

You fetch() from the cursor. The cursor is what .find() returns.

Collection.find() … returns a cursor that you can publish, do a count, map over it with a forEach command.

Example:

Collection.find({ your query }, { your options }).count()
Collection.find().forEach(d => d._id) // returns an array of matched document ids.

Collection.find() only finds but does not retrieve any documents. To retrieve your documwnt, see next …

Collection.find().fetch() returns your result as an array of matched document (objects)

On the other hand, Collection.findOne() returns your one matched document as an object or undefined.

I really thing you should read the document and go through yhe TODO training example.

2 Likes

Yeah I really need more practice…

but thank you for the help!

Hi @miki11 I read this entire thread and I believe no one has addressed a couple of basic questions you’ve made:

The [ ] in the Meteor.call definition do not mean “array” but rather “optional”. This is a very common notation in API documentation.
You can pass as many arguments as you want to a method, and these args can be of any type. You can as well pass a callback as the last parameter to your Method.call call, to do something with the result of that call. Nor the arguments nor the callback need to be inside an array (and in particular, if you put the callback inside an array it may get interpreted as an argument instead I believe)

@paulishca already answered the basics on find & fetch but to me it seems you have a deeper missunderstanding on what is going on (no disrespect intended).

A method (anything defined inside Metheor.methods) is basically an API. So what it returns its completely up to you. It doesn’t have to return anything in particular (as a custom defined API).

A publication (anything defined with Meteor.publish) on the other side, has to return a cursor. That means, every publication definition must end with return Collection.find(searchObject, optionsObject).

These are very basic Meteor concepts so yes, besides more practice I’d say you need to take a deeper, slower dive into the docs in order to better understand the concepts. Otherwise you may end up wasting a lot of time debugging. Don’t know if you’ve done it but following the meteor tutorial for the ToDo App may help clarify all the concepts and the usual way of using things

Regards

1 Like

I still understood incorrectly so your explanation helps me a lots!

Thank you for the help!