meteor0.9.1.1 – 从json端点填充到服务器端集合

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

我一直在收到错误消息告诉我,我需要把服务器端收集更新function放入光纤,Meteor.bindEnvironment或Meteor._callAsync。

我感到困惑,因为没有清楚简明的解释告诉我这些事情到底是什么,他们是什么,他们何时何时被弃用,或者他们的使用是否是好的做法。

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

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

有点伪码:

1)设置Mongo.Collection项目列表

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

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

Collections.js看起来像下面的内容。 在光纤中包装插入function似乎压制错误消息,但是没有数据被插入到数据库中。

 /** 

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

 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年有很多build议,但我不愿意使用它们,因为meteor是不断变化的,甚至一个小小的更新可以打破很多东西。

谢谢

好消息是:解决scheme实际上比迄今为止编写的所有代码简单得多。

根据我掌握的知识,你写了一个httpFetch函数,它使用用HTTP.get装饰的HTTP.get的asynchronous版本。 然后你试图在一个新的Fiber运行你的集合更新,因为asynchronousHTTP.get调用引入了一个callback,继续使用promise。

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

 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

我现在有这个工作。 看来问题是我的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函数来运行callback。

在这个callback里面是parsing获取的数据并将其插入到我的集合中的代码,这是正在工作的关键部分。

下面是修改后的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); } ); } 

};