Reputation: 23
How do I call a Meteor method with a object as an argument, if this is at all possible?
Here is what I'm struggling with if it helps
I have the method:
'user.some.update.position'(coords) {
console.log('method: ', 'user.some.update.position');
console.log('this.userid: ', this.userId);
console.log('coords: ', coords);
check(coords, Object);
check(coords.latitude, Number);
check(coords.longitude, Number);
check(coords.accuracy, Number);
if (!this.userId)
throw new Meteor.Error('Not logged in', 'You are not logged in, please log in');
Meteor.users.update({
_id: this.userId
}, {
$set: {
coords,
lastUpdated: new Date()
}
});
return coords;
}
Which I want to call from the client like this:
> var coords = Geolocation.currentLocation().coords
undefined
> coords
Coordinates {latitude: 58.2441766, longitude: 8.376727899999999, altitude: null, accuracy: 25, altitudeAccuracy: null…}
> Meteor.call('user.some.update.position', coords, function(err, res) {if(err) console.log('err: ', err); if(res) console.log('res: ', res);})
undefined
VM7572:2 err: errorClass {error: 400, reason: "Match failed", details: undefined, message: "Match failed [400]", errorType: "Meteor.Error"}
But when I do that the server complains that coords
is a empty object like this:
method: user.some.update.position
I20160220-15:49:34.226(1)? this.userid: nHqj3zaSWExRmqBZq
I20160220-15:49:34.226(1)? currentLocation: {}
I20160220-15:49:34.227(1)? Exception while invoking method 'user.some.update.position' Error: Match error: Expected number, got undefined
I20160220-15:49:34.227(1)? at Object.check (packages/check/match.js:33:1)
I20160220-15:49:34.228(1)? at [object Object]._meteorMeteor.Meteor.methods.user.some.update.position (server/methods/drivers.js:36:5)
I20160220-15:49:34.228(1)? at packages/check/match.js:103:1
I20160220-15:49:34.228(1)? at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
I20160220-15:49:34.228(1)? at Object.Match._failIfArgumentsAreNotAllChecked (packages/check/match.js:102:1)
I20160220-15:49:34.228(1)? at maybeAuditArgumentChecks (packages/ddp-server/livedata_server.js:1695:18)
I20160220-15:49:34.228(1)? at packages/ddp-server/livedata_server.js:708:19
I20160220-15:49:34.228(1)? at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
I20160220-15:49:34.228(1)? at packages/ddp-server/livedata_server.js:706:40
I20160220-15:49:34.229(1)? at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
I20160220-15:49:34.229(1)? Sanitized and reported to the client as: Match failed [400]
And the client complains:
err: errorClass {error: 400, reason: "Match failed", details: undefined, message: "Match failed [400]", errorType: "Meteor.Error"}
Edit: I am using ES6 and object destructuring.
Upvotes: 2
Views: 728
Reputation: 16478
The object that you are getting from the geolocation request implements the Coordinates interface. You cannot assume anything else about it.
In your case, the object is likely not serializable via EJSON, and therefore cannot be used as a Meteor method call argument as it is.
The method call routine calls EJSON.clone()
and given the Coordinates
object, it returns an empty object.
> EJSON.clone(coordinates)
Object {}
In Chrome's implementation, I assume that the properties are "owned" deeper in the prototype chain. EJSON relies on underscore's _.keys
function when cloning, which in turn lists the object's own properties.
> coordinates.hasOwnProperty("latitude")
false
> "latitude" in coordinates
true
Since creating a custom EJSON type for it seems unrealistic, you can do as @ChristianFritz suggested or use underscore's _.pick
.
> _.pick(coordinates, ['latitude', 'longitude', 'accuracy'])
Object {latitude: 12.1212, longitude: 34.3434, accuracy: 50}
Upvotes: 0
Reputation: 4049
Both the answers by Christian and Faysal contain valid information, I just want to expand on them a little:
The actual exception you're seeing, Error: Match error: Expected number, got undefined
, is happening because of this line of code:
check(coords.latitude, Number);
.
In your console log, you can see that coords is just an empty object:
I20160220-15:49:34.226(1)? currentLocation: {}
So when your check() method checks the currentLocation for coords.latitude, it throws the exception because coords.latitude is of type undefined, not of type Number like you said it would be in the check() statement.
Once you fix that, Christian pointed out that you'll get another error because of your update statement. MongoDB's $set requires you to pass in an object with the schema { $set: { <field1>: <value1>, ... } }
. You are passing in: { $set: {}, lastUpdated: <A valid Date> }
. Because that empty object doesn't match the field: value
schema $set is expecting, it'll throw an exception. As he says, you'll need to either parse out that object into individual properties or pass it to a property itself.
Upvotes: 1
Reputation: 21364
what is $set: { coords,
supposed to do? you can't do that. You need to take the content of that object apart and put it back together into the $set
. Assuming that coords = {lat: 1234, lng: 2345}
(or similar), you would do:
$set: {
lat: coords.lat,
lng: coords.lng,
...
or you can just add it as a sub-object;
$set: {
coords: coords,
Upvotes: 1
Reputation: 1542
It's clear from your error message that your object has nothing in it. please look at the 4th line of your error message, currentLocation
contains no property. Sending a valid object will solve the problem.
Upvotes: 1