2

我正在编写一个包作为我正在处理的一个小型应用程序的一部分,我需要做的一件事是从端点获取 json 数据并将其填充到服务器端集合。

我一直收到错误消息,告诉我需要将服务器端集合更新函数放入 Fiber、Meteor.bindEnvironment 或 Meteor._callAsync。

我很困惑,因为没有清晰简洁的解释告诉我这些到底是做什么的,它们是什么,是否以及何时被弃用,或者它们的使用是否是好的做法。

这是我的包文件中重要的内容

api.addFiles([
    '_src/collections.js'
], 'server');

一些伪代码:

1) 设置 Mongo.Collection 项目列表

2) 使用我编写的名为 httpFetch() 的函数填充这些,并为每个集合运行它,如果获取成功,则返回已解决的承诺。

3) 在下划线 each() 循环中调用此 httpFetch 函数,遍历我拥有的每个集合,获取 json 数据,并尝试将其插入服务器端 Mongo DB。

Collections.js 如下所示。将插入函数包装在 Fiber 中似乎可以抑制错误消息,但没有数据被插入到数据库中。

/**

* 服务器端组件向远程 * 端点发出请求以填充服务器端 Mongo 集合。* * @class 服务器 * @static */ 服务器 = {

Fiber: Npm.require('fibers'),

/**
 *  Collections to be populated with content
 *  
 *  @property Collections
 *  @type {Object}
 */
Collections: {
    staticContent:  new Mongo.Collection('staticContent'),
    pages:          new Mongo.Collection('pages'),
    projects:       new Mongo.Collection('projects'),
    categories:     new Mongo.Collection('categories'),
    formations:     new Mongo.Collection('formations')  
},

/**
 *  Server side base url for making HTTP calls
 *  
 *  @property baseURL
 *  @type {String}
 */
baseURL: 'http://localhost:3000',

/**
 *  Function to update all server side collections
 *
 *  @method updateCollections()
 *  @return {Object} - a resolved or rejected promise
 */
updateCollections: function() {

    var deferred = Q.defer(),
        self = this,
        url = '',
        collectionsUpdated = 0;

    _.each(self.Collections, function(collection) {

        // collection.remove();
        url = self.baseURL + '/content/' + collection._name + '.json';

        self.httpFetch(url).then(function(result) {

            jsonData = EJSON.parse(result.data);

            _.each(jsonData.items, function(item) {
                console.log('inserting item with id ', item.id);
                self.Fiber(function() {
                    collection.update({testID: "Some random data"}
                });
            });

            deferred.resolve({
                status: 'ok',
                message: 'Collection updated from url: ' + url
            });

        }).fail(function(error) {
            return deferred.reject({
                status: 'error',
                message: 'Could not update collection: ' + collection._name,
                data: error
            });
        });

    });

    return deferred.promise;
},

/**
 *  Function to load an endpoint from a given url
 *
 *  @method httpFetch()
 *  @param  {String} url
 *  @return {Object} - A resolved promise if the data was
 *                     received or a rejected promise.
 */
httpFetch: function(url) {

    var deferred = Q.defer();

    HTTP.call(
        'GET',
        url,
        function(error, result) {
            if(error) {
                deferred.reject({
                    status: 'error',
                    data: error
                });
            }
            else {
                deferred.resolve({
                    status: 'ok',
                    data: result.content
                }); 
            }
        }
    );
    return deferred.promise;
}

};

我仍然真的被困在这个问题上,从我之前阅读其他帖子的尝试来看,我似乎仍然无法弄清楚让这个工作或让它工作的“最佳实践”方式。

2011/2012 年有很多建议,但我不愿意使用它们,因为 Meteor 不断变化,即使是一个小的更新也会破坏很多东西。

谢谢

4

2 回答 2

1

好消息:该解决方案实际上比您迄今为止编写的所有代码都简单得多。

据我所知,您编写了一个函数,该函数使用了带有 promisehttpFetch的异步版本。HTTP.get然后,您尝试在 new 中运行您的集合更新,Fiber因为 asyncHTTP.get调用引入了一个通过使用 promise 继续的回调then

您首先需要做的是使用HTTP.get服务器上可用的 SYNCHRONOUS 版本,这将允许您编写这种类型的代码:

updateCollections:function(){
  // we are inside a Meteor.method so this code is running inside its own Fiber
  _.each(self.Collections, function(collection) {
    var url=// whatever
    // sync HTTP.get : we get the result right away (from a
    // code writing perspective)
    var result=HTTP.get(url);
    // we got our result and we are still in the method Fiber : we can now
    // safely call collection.update without the need to worry about Fiber stuff
  });

您应该仔细阅读有关 HTTP 模块的文档:http: //docs.meteor.com/#http_call

于 2014-09-15T08:20:32.227 回答
0

我现在有这个工作。看来问题在于我的 httpFetch 函数返回了一个承诺,这导致了错误:

"Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment."

当 HTTP.get() 调用成功或错误时,我更改了此 httpFetch 函数以运行回调。

在这个回调中是解析获取的数据并将其插入到我的集合中的代码,这是现在工作的关键部分。

下面是修改后的 Collections.js 文件,其中包含解释所有内容的注释。

Server = {

/**
 *  Collections to be populated with content
 *  
 *  @property Collections
 *  @type {Object}
 */
Collections: {
    staticContent:  new Mongo.Collection('staticContent'),
    pages:          new Mongo.Collection('pages'),
    projects:       new Mongo.Collection('projects'),
    categories:     new Mongo.Collection('categories'),
    formations:     new Mongo.Collection('formations')  
},

/**
 *  Server side base url for making HTTP calls
 *  
 *  @property baseURL
 *  @type {String}
 */
baseURL: 'http://localhost:3000',

/**
 *  Function to update all server side collections
 *
 *  @method updateCollections()
 *  @return {Object} - a resolved or rejected promise
 */
updateCollections: function() {

    var deferred = Q.defer(),
        self = this,
        collectionsUpdated = 0;

    /**
     *  Loop through each collection, fetching its data from the json 
     *  endpoint.
     */
    _.each(self.Collections, function(collection) {

        /**
         *  Clear out old collection data
         */
        collection.remove({});

        /**
         *  URL endpoint containing json data. Note the name of the collection
         *  is also the name of the json file. They need to match.
         */
        var url = self.baseURL + '/content/' + collection._name + '.json';

        /**
         *  Make Meteor HTTP Get using the function below.
         */
        self.httpFetch(url, function(err, res) {

            if(err) {
                /**
                 *  Reject promise if there was an error
                 */
                deferred.reject({
                    status: 'error',
                    message: 'Error fetching content for url ' + url,
                    data: err
                });
            }
            else {
                /**
                 *  Populate fetched data from json endpoint
                 */
                var jsonData = res.content;
                    data = EJSON.parse(res.content);

                /**
                 *  Pick out and insert each item into its collection
                 */
                _.each(data.items, function(item) {
                    collection.insert(item);
                });

                collectionsUpdated++;

            }

            if(collectionsUpdated === _.size(self.Collections)) {

                /**
                 *  When we have updated all collections, resovle the promise
                 */
                deferred.resolve({
                    status: 'ok',
                    message: 'All collections updated',
                    data: {
                        collections: self.Collections,
                        count: collectionsUpdated
                    }
                });
            }
        });

    });

    /**
     *  Return the promise
     */

    return deferred.promise;
},

/**
 *  Function to load an endpoint from a given url
 *
 *  @method httpFetch()
 *  @param  {String} url
 *  @param  {Function} cb - Callback in the event of an error
 *  @return undefined
 */
httpFetch: function(url, cb) {

    var res = HTTP.get(
        url, 
        function(error, result) {
            cb(error, result);
        }
    );
}

};

于 2014-09-15T11:19:29.433 回答