简体   繁体   English

为什么用非空对象调用Meteor.method时服务器会得到一个空对象?

[英]Why is the server getting an empty object when calling Meteor.method with a non-empty object?

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: 但是,当我这样做时,服务器会抱怨coords是一个空对象,如下所示:

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. 编辑:我正在使用ES6和对象分解。

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. 请查看错误消息的第四行, currentLocation包含任何属性。 Sending a valid object will solve the problem. 发送有效的对象将解决问题。

what is $set: { coords, supposed to do? $set: { coords,是什么$set: { coords,应该做什么? you can't do that. 你不能那样做。 You need to take the content of that object apart and put it back together into the $set . 您需要拆开该对象的内容,然后将其放回$set Assuming that coords = {lat: 1234, lng: 2345} (or similar), you would do: 假设coords = {lat: 1234, lng: 2345} (或类似名称),您可以这样做:

$set: {
  lat: coords.lat,
  lng: coords.lng,
  ...

or you can just add it as a sub-object; 或者您可以将其添加为子对象;或者

$set: {
  coords: coords,

Both the answers by Christian and Faysal contain valid information, I just want to expand on them a little: 克里斯蒂安(Christian)和费萨尔(Faysal)的答案都包含有效信息,我只想对它们作一点扩展:

The actual exception you're seeing, Error: Match error: Expected number, got undefined , is happening because of this line of code: 由于以下代码行,您正在看到的实际异常是Error: Match error: Expected number, got undefined

check(coords.latitude, Number); .

In your console log, you can see that coords is just an empty object: 在控制台日志中,您可以看到coords只是一个空对象:

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. 因此,当您的check()方法检查currentLocation中的coords.latitude时,它会引发异常,因为coords.latitude的类型未定义,而不是Number类型,就像您所说的那样在check()语句中。

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>, ... } } . MongoDB的$ set要求您传入具有模式{ $set: { <field1>: <value1>, ... } } You are passing in: { $set: {}, lastUpdated: <A valid Date> } . 您要传入: { $set: {}, lastUpdated: <A valid Date> } Because that empty object doesn't match the field: value schema $set is expecting, it'll throw an exception. 因为该空对象与该field: value不匹配field: value模式$ set需要,所以它将引发异常。 As he says, you'll need to either parse out that object into individual properties or pass it to a property itself. 正如他所说,您将需要将该对象解析为单独的属性,或者将其传递给属性本身。

The object that you are getting from the geolocation request implements the Coordinates interface. 您从地理位置请求中获取的对象将实现Coordinates接口。 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. 在您的情况下,该对象可能无法通过EJSON进行序列化,因此不能按原样用作Meteor方法调用参数。

The method call routine calls EJSON.clone() and given the Coordinates object, it returns an empty object. 方法调用例程将调用EJSON.clone()并给定Coordinates对象,它将返回一个空对象。

> EJSON.clone(coordinates)
Object {}

In Chrome's implementation, I assume that the properties are "owned" deeper in the prototype chain. 在Chrome的实现中,我假设属性在原型链的更深处“拥有”。 EJSON relies on underscore's _.keys function when cloning, which in turn lists the object's own properties. 克隆时,EJSON依赖于下划线的_.keys函数,该函数又列出了对象自己的属性。

> 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 . 由于为此创建自定义EJSON类型似乎是不现实的,因此您可以按照@ChristianFritz的建议进行操作,也可以使用下划线的_.pick

> _.pick(coordinates, ['latitude', 'longitude', 'accuracy'])
Object {latitude: 12.1212, longitude: 34.3434, accuracy: 50}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM