meteor findOne or find returns undefined - meteor

I'm trying to do some validation prior to loading the main page. To do this I need to find a document that I have confirmed, exist in the Mongo Collection. Unfortunately finding the document in the client.js doesn't seem to work. In my opinion the client and server collection are not in sync. Based on similar articles i have read I made many changes without success. Here is a quick summary of what I have tried.
Option1: Try to find the record in the client side and not using auto-subscribe: record not found.
In app.js
credentialToken = "2KcNCRzpTHzyZ1111";
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to ares_sso.";
};
Meteor.startup(function () {
var results = Meteor.findrec(credentialToken);
console.log("results:",results); //results is undefined.
});
Template.hello.events({
'click input': function () {
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
In /client/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.subscribe("crs");
Meteor.findrec = function(credentialToken) {
target = {credentialtoken:credentialToken};
recfound = crs_collection.findOne(target);
//No luck with find either.
//recfound = crs_collection.find({credentialtoken:credentialToken}, {limit:1}).fetch()[0];
console.log("recfound:",recfound); //returns recfound is undefined.
return recfound;
}
In /server/server.js
crs_collection = new Meteor.Collection("crs");
Meteor.publish("crs", function(){
return crs_collection.find();
});
Option2: Next I did the find in the server side, using a method "server_recfind" which worked but I'm not able get the content to the client.
In app.js
credentialToken = "2KcNCRzpTHzyZ1111";
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to ares_sso.";
};
Meteor.startup(function () {
var results = Meteor.call('server_findrec',credentialToken);
console.log("results=",results); // also returns undefined
});
Template.hello.events({
'click input': function () {
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
In /client/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.subscribe("crs");
In /server/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.publish("crs", function(){
return crs_collection.find();
});
// Using Sync which finds the record but how do I sent the content to the client?
Meteor.methods ({
'server_findrec': function(credentialToken) {
// tried unblock but didnt work
//this.unblock();
var rec = crs_collection.findOne({'credentialtoken': credentialToken});
console.log("INSIDE server findrec rec=",rec); //shows content found
// tried flush but it didn't do anything
crs_collection.flush;
return rec; //rec not returning to the client
}
})
Option3: Frustrated and since I was able to find the document record with the server method. I tried adding global variables to delivery the content to the client side. Unfortunately it didn't work
In app.js
credentialToken = "2KcNCRzpTHzyZ1111";
//added global variables
c1 = '';
c2 = '';
c3 = ''
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to ares_sso.";
};
Meteor.startup(function () {
var results = Meteor.call('server_findrec',credentialToken);
console.log("results=",results); // also returns undefined
console.log("c1=",c1);
console.log("c2=",c2);
console.log("c3=",c3);
});
Template.hello.events({
'click input': function () {
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
In /client/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.subscribe("crs");
In /server/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.publish("crs", function(){
return crs_collection.find();
});
// Using Sync which finds the record but how do I sent the content to the client?
Meteor.methods ({
'server_findrec': function(credentialToken) {
// tried unblock but didnt work
//this.unblock();
var rec = crs_collection.findOne({'credentialtoken': credentialToken});
console.log("INSIDE server findrec rec=",rec); //shows content found
c1 = rec.cont1;
c2 = rec.cont2;
c3 = rec.cont3;
//confirm that c1,c2 and c3 have content
console.log(In server_findrec c1=",c); //shows content
console.log(In server_findrec c2=",c2); //shows content
console.log(In server_findrec c3=",c3); //shows content
// tried flush to sync to client...didn't work
crs_collection.flush;
return rec; //rec not returning to the client
}
})
There is a lot more code, so I have assembled all of the above hoping it gives you a clear picture of what I have tried and what I'm trying to do. I'm sorry if I made a mistake in the process.
Overall it will be great to know what am I doing wrong? I believe the 3 scenarios should work. Any help or recommendation will be appreciated.
I'm using Meteor Release 0.7.1.2, no CoffeeScript.
Thank you all

You're making two mistakes:
Define crs_collection once, and make sure its in a file thats executed on the client AND the server. It should be defined globally.
crs_collection must be defined before your pub/sub code. Meteor executes files in the lib directory first, so its best to put your collection code there.
That's really all there is to it. I'm happy to provide an example if needed.

Related

Meteor wrapAsync returning undefined to external service using php connector

I've been stuck on this for way too long. Can anyone help show me why my wrapasync method is returning as "undefined"? I'm trying to make a call to Facebook api and have used a php connector that my meteor app should use to talk to the Facebook PHP SDK. My app talks to the my php file and returns simple functions. But when I actually call the external service it comes back as undefined, although when I run the php function in php it comes out fine and returns expected results. Here's the code, everything is server-side:
var phpAsync = function() {
var execPhp = Meteor.npmRequire('exec-php');
execPhp('C:/xampp/htdocs/xampp/Facebook/file.php', function(error, php, output){
// php now contain user defined php functions.
php.me( function(error, result, output, printed){
// `result` is return value of `my_own_php_function` php function.
console.log(result);
return result;
});
});
};
Meteor.methods({
phpConnect: function () {
var phpSync = Meteor.wrapAsync(phpAsync);
var result = phpSync();
console.log(result);
return result
}
});
The function that is passed in to Meteor.wrapAsync should have callback as the final parameter. From the docs,
Wrap a function that takes a callback function as its final parameter.
The signature of the callback of the wrapped function should be
function(error, result){}
So you should do something like this,
var phpSync = function() {
var execPhp = Meteor.npmRequire('exec-php');
var execPhpSync = Meteor.wrapAsync(execPhp);
var php = execPhpSync('C:/xampp/htdocs/xampp/Facebook/file.php');
php.meSync = Meteor.wrapAsync(php.me);
var result = php.meSync();
console.log(result);
return result;
};
Meteor.methods({
phpConnect: function () {
var result = phpSync();
console.log(result);
return result;
}
});
OR
if you want other stuff like output and printed then you do it like this
var phpAsync = function(cb) {
var execPhp = Meteor.npmRequire('exec-php');
execPhp('C:/xampp/htdocs/xampp/Facebook/file.php', function(error, php, output){
//IMPORTANT: you need to call php.me only if there is no error
// php now contain user defined php functions.
php.me( function(error, result, output, printed){
// `result` is return value of `my_own_php_function` php function.
if (typeof cb === "function) {
cb(error, {
result: result,
output: output,
printed: printed
});
}
});
});
};
Meteor.methods({
phpConnect: function () {
var phpSync = Meteor.wrapAsync(phpAsync);
var result = phpSync();
console.log(result.result, result.output, result.printed);
return result.result;
}
});

insert still works after Meteor.logout

This Meteor app has the insecure and autopublish removed and accounts-password added.
It uses Accounts.createUser({username: someName, password: somePwrd});
It avoids using allow/deny and uses instead Meteor.call to insert documents because reading in the docs, it says that
Server code is trusted and isn't subject to allow and deny restrictions. That includes methods that are called with Meteor.call — they are expected to do their own access checking rather than relying on allow and deny.
But when I fire up the Meteor.logout(), I am still able to insert new documents to Tasks1 collection. How can that be? I though logout will stop inserting any new documents. How can I fix it? Thanks
///////////////////////////
//both/both.js
///////////////////////////
Tasks1 = new Mongo.Collection('tasks1');
///////////////////////////
//server/server.js
///////////////////////////
Meteor.publish('tasks1', function(){
return Tasks1.find({userId: this.userId});
});
Meteor.methods({
addTasks1: function (doc) {
Tasks1.insert(doc);
}
});
///////////////////////////
//client/client.js
///////////////////////////
Template.footer.events({
'click button': function () {
if ( this.text === "SUBMIT" ) {
var inputs = document.getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++) {
var params = {};
params[inputs[i].name] = inputs[i].value;
Meteor.call('addTasks1', params);
}
}
}
});
Template.mainMenu.events({
'click #logout': function () {
Meteor.logout();
}
});
In your server addTasks1 method, you should first check if the user is a user like so:
Meteor.methods({
addTasks1: function(doc) {
if (!Meteor.userId()) {
throw new Meteor.Error("Not Authorized");
} else {
Tasks1.insert(doc);
}
}
})
Logout alone doesn't stop users from being able to insert. You must edit your method code to achieve this.
addTasks1: function (doc) {
if (Meteor.userId()) {
Tasks1.insert(doc);
}
}

Meteor wrapasync save Twitter REST response to Mongo collection giving an error "Error: Meteor code must always run within a Fiber."

I am trying to use Twitter REST API GET followers/ids and save it to Mongo using Mongo collection insert method
Code inside /server/server.js:
Meteor.startup(function () {
// code to run on server at startup
TwitterFollowersIDsCollecions = new Mongo.Collection("twitterFollowersIDs");
var Twit = Meteor.npmRequire('twit');
var T = new Twit({
consumer_key: '###',
consumer_secret: '###',
access_token: '###',
access_token_secret: '###'
});
var getTwitterFollowersIDsAsync = function (screenname, cb) {
T.get('followers/ids', { screen_name: screenname }, function (err, data, response) {
console.log(data);
var vids = data.ids;
for(var i in vids) {
TwitterFollowersIDsCollecions.insert({
twitterFollowerID:vids[i]
});
}
}
);
};
Meteor.methods({
getTwitterFollowersIDsCollectionsClient : function (screenname){
var getTwitterFollowersIDsNow = Meteor.wrapAsync(getTwitterFollowersIDsAsync);
var result = getTwitterFollowersIDsNow('meteorjs');
console.log(result);
return result;
}
});
});
Error in server console:
Error: Meteor code must always run within a Fiber.
Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.
Objective is to save twitter followers to a Mongo collection.
Meteor v. 1.1.0.2
Meteor packages:
meteor-platform
autopublish
insecure
differential:vulcanize
accounts-twitter
accounts-ui
meteorhacks:npm
npm-container
npm modules being used inside Meteor through meteorhacks:npm: "twit": "1.1.20" (added inside packages.json)
**UPDATE Second attempt **
Meteor.startup(function () {
// code to run on server at startup
TwitterFollowersIDsCollecions = new Mongo.Collection("twitterFollowersIDs");
var Twit = Meteor.npmRequire('twit');
var T = new Twit({
consumer_key: '###',
consumer_secret: '###',
access_token: '###',
access_token_secret: '###'
});
Meteor.methods({
// this is the server method called from the client
getTwitterFollowersIDsCollectionsClient : function (){
setTimeout(function(){
Meteor.call('getTwitterFollowersIDsNow', 'meteorjs');
},10);
return;
},
getTwitterFollowersIDsNow : function (screenname) {
T.get('followers/ids', { screen_name: screenname }, function (err, data, response) {
console.log(data);
});
}
});
});
I'm then calling the below code from browser console:
Meteor.call('getTwitterFollowersIDsCollectionsClient');
The server crashes with the same error:
Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.
UDPATE:
getTwitterFollowersIDsCollectionsClient : function (screenname){
Meteor.setTimeout(function(screenname){
T.get('followers/ids', { screen_name: screenname }, Meteor.bindEnvironment(function (err, data, response) {
console.log("from getTwitterFollowersIDsCollectionsClient : "+data.ids);
var vids = data.ids;
for(var i in vids)
{
TwitterFollowersIDsCollecions.insert({
twitterFollowerID:vids[i]
});
}
return data;
}));
},10);
return;
}
Added Meteor.bindEnvironment to T.get callback method. This code worked and I was able to save the follower IDs to a mongo collection
Glad you got it working, but I played around with this and Meteor provides another, super easy way: wrapAsync. At least, it was easy once I figured it out! Here's the server code I wound up with -
var T = new TwitMaker({
consumer_key: '...'
, consumer_secret: '...'
, access_token: '...'
, access_token_secret: '...'
})
var wrapGet = Meteor.wrapAsync(T.get, T);
Meteor.methods({
getTwitImg: function(target) {
data = wrapGet('users/show', {screen_name: target});
if (data) {
img_url = data['profile_image_url'];
US.update({twitter: target}, {$set: {'targetImg': img_url}});
return img_url;
}
}
});
For the client and template code see this gist: https://gist.github.com/DanAncona/a09ce375e48bfa8efeca
Your code is a bit confusing. It seems like you're trying to execute a web service call async, but still return the result immediately (which won't work).
First of all, you probably wouldn't need to wrap the function to fetch the followers in an async block.
If you want your server method to return something immediately to the client after it has been called, I'd use a Meteor.setTimeout (see What's the point of Meteor.setTimeout() vs just setTimeout()?) block and call another method to do the fetching:
Meteor.methods({
// this is the server method called from the client
getTwitterFollowersIDsCollectionsClient : function (screenname){
Meteor.setTimeout(function() {
Meteor.call('getTwitterFollowersIDsNow', 'meteorjs');
}, 10);
return;
},
getTwitterFollowersIDsNow : function (screenname) {
T.get('followers/ids', { screen_name: screenname }, function (err, data, response) {
console.log(data);
var vids = data.ids;
for(var i in vids) {
TwitterFollowersIDsCollecions.insert({
twitterFollowerID:vids[i]
});
}
}
}
});
Ideally you would use a template helper to retrieve your followers from your collection. Due to these kind of helpers being reactive, you could just call the server method from the client and let the reactivity of Meteor solve your problem of returning the followers via the helper (which is re-executed/re-rendering the template on data change).
try calling:
var wrappedInsert = Meteor.bindEnvironment(function(tweet) {
TweetsCollection.insert(tweet);},
"Failed to insert tweet into Posts collection.");
from inside of api callback
getTwitterFollowersIDsNow : function (screenname) {
T.get('followers/ids', { screen_name: screenname }, function (err, data, response) {
for(var i in data)
{
wrappedInsert(data[i]);
}
});
}

Implement added, changed and removed server side

Context : I am using a Collection Params to call method from the Server to a C app. The C app does its stuff and then calls the server by RPC to send me the results. With the result, I get the Params ID to delete the corresponding element.
With the deletion of the Element of Params, the C app gets a removed message. I want to prevent this behavior to avoid overloading the C app of messages.
I've thinked about implementing the removed event into the Publish method on the server to prevent the server from informing the C app. I just want the C app to be inform about added events.
On the Meteor Doc, there is an example of implementation of added and removed but I don't understand it. Can someone help me ?
I've tried this (don't work at all) :
Meteor.publish('expert_mode_parameters', function ()
{
var self = this;
var handle = Expert_Mode_Parameters.find().observeChanges({
added: function ()
{
return Expert_Mode_Parameters.find();
},
removed: function ()
{
return [];
}
});
self.ready();
self.onStop(function () {
handle.stop();
});
}
It looks like your goal is to subscribe to a data set but only receive added messages, not changed or removed.
The below code should do this:
Meteor.publish('expert_mode_parameters', function () {
var self = this;
var handle = Expert_Mode_Parameters.find().observe({
added: function (document) {
self.added("expert_mode_parameters", document._id, document);
}
});
self.ready();
self.onStop(function () {
handle.stop();
});
}
The concept is, you're watching the results of Expert_Mode_Parameters.find() and then calling self.added(document) when there is a new item. The same thing can easily be expanded to include changed.

SQLite with Cordova: Unable to initialize database on other pages

I'm playing around SQLite in Cordova as part of an upskilling process for work and I'm hitting a brick wall. The various articles I've read around initializing the SQLite plugin from Chris Brody is to always call it in after device ready, but all examples are around the index page. What if I need to populate data on the products.html page, without also calling all other initialization calls to the database?
What I mean is, given the following JS file, called core.js:
var db,
app = {
// Application Constructor
initialize: function() {
this.bindEvents();
},
// Bind Event Listeners
//
// Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// deviceready Event Handler
//
// The scope of 'this' is the event. In order to call the 'receivedEvent'
// function, we must explicitly call 'app.receivedEvent(...);'
onDeviceReady: function () {
app.receivedEvent('deviceready');
},
// Update DOM on a Received Event
receivedEvent: function (id) {
app.initdb();
console.log('Received Event: ' + id);
},
initdb: function () {
try {
db = window.sqlitePlugin.openDatabase({ name: 'meatblock.db' });
if (!db) {
console.error('Database unable to initialize, it either does not exist or is null');
return false;
}
else {
return true;
}
}
catch (err) {
console.error('Database initialization error: ' + err);
}
}
};
In the receivedEvent, which bubbles up, I call my initdb() function that calls the plugin and opens up the database.
The process works like a charm, in this method I can write my SQL SELECT statement to retrieve data and display it on the page without error.
As soon as I mode the TX script outside of this, it does not work. I even call the initdb() function before it, and still, I get an error saying that it cannot open database on undefined.
in core.js, at the top, I define db globally, as some have suggested in various other blogs, but the following code, out side of the receivedEvent just does not work:
jQuery(document).ready(function ($) {
app.initdb();
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM table_1', [], function (tx, results) {
var _data = results;
for (var i = 0; i < results.rows.length; i++) {
var row = results.rows.item(i);
$li = $('<li></li>').text(row);
$('.table-output').append($li);
}
}, function (e) {
alert('an error occurred trying to retrieve database from table_1');
});
}, function (e) {
alert('an error occurd');
}, function () {
alert('all done');
});
});
after calling app.initdb() just before I handle a TX, my assumption is that it would open the database again, as at this point, right? Even if I don't use jQuery's ready statement, it just does not work, without jQuery:
app.initdb();
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM table_1', [], function (tx, results) {
var _data = results;
for (var i = 0; i < results.rows.length; i++) {
var row = results.rows.item(i);
$li = jQuery('<li></li>').text(row);
jQuery('.table-output').append($li);
}
}, function (e) {
alert('an error occurred trying to retrieve database from table_1');
});
}, function (e) {
alert('an error occurd');
}, function () {
alert('all done');
});
I'm sure there is something that I'm not getting about this. Is it impossible to open the database and retrieve data outside of the device ready statement?

Resources