My goal is to insert device token into db. The method succeeds on the client but fails on the server side. I have no idea why.
// lib/meteor_methods.js
Meteor.methods({
savePushTokens: function(myToken) {
console.log("Saving the token.")
Tokens.insert({token: myToken}, function(error, result) {
if (error) {
console.log(error);
}
else {
console.log(result);
}
});
console.log("Token is now saved!");
}
})
// client/push_notifications.js
...
function tokenSuccessHandler(result) {
console.log('token success result ' + result);
window.localStorage.setItem('deviceToken', result);
// API call to store token on your DB
Meteor.call('savePushTokens', result)
console.log(Tokens.find().fetch());
}
...
Please see the whole file: https://github.com/mvaisanen/SimplePushApp/blob/pushplugin/client/push_notifications.js
Xcode console output
2015-01-22 10:27:51.165 myapp[33366:5680153] token success result
077f2ea72eb6b2dfc381ce27f2eb12e2ee8ee68f7eeb90f7f2f10f1d99cd140e
2015-01-22 10:27:51.166 myapp[33366:5680153] Saving the token.
2015-01-22 10:27:51.166 myapp[33366:5680153] zp6vkrN5M4HtKF9NF
2015-01-22 10:27:51.166 myapp[33366:5680153] Token is now saved!
2015-01-22 10:27:51.166 myapp[33366:5680153] [{"token":"077f2ea72eb6b2dfc381ce27f2eb12e2ee8ee68f7eeb90f7f2f10f1d99cd140e","_id":"zp6vkrN5M4HtKF9NF"}]
Everything seems fine.
However, if I query database inside meteor shell, client or server, the result is empty collection. (> Tokens.find().fetch()
[]).
If I run the method on the server side, it actually never runs. See below.
// lib/meteor_methods.js
Meteor.methods({
savePushTokens: function(myToken) {
console.log("Saving the token.")
if (Meteor.isServer) {
Tokens.insert({token: myToken}, function(error, result) {
if (error) {
console.log(error);
}
else {
console.log(result);
}
});
console.log("Token is now saved!");
}
}
});
Xcode console output
2015-01-22 10:32:59.290 myapp[33375:5681416] token success result 077f2ea72eb6b2dfc381ce27f2eb12e2ee8ee68f7eeb90f7f2f10f1d99cd140e
2015-01-22 10:32:59.291 myapp[33375:5681416] Saving the token.
2015-01-22 10:32:59.291 myapp[33375:5681416] []
Any idea? The full repo is here https://github.com/mvaisanen/SimplePushApp/tree/pushplugin
UPDATE
I have autopublish and insecure installed.
I start the app with meteor run ios-device --mobile-server 192.168.1.6:3000.
I can manually insert data to db via meteor shell or meteor mongo.
I have also tried to check for tokens in meteor mongo:
$ meteor mongo
MongoDB shell version: 2.4.12
connecting to: 127.0.0.1:3001/meteor
meteor:PRIMARY> db.tokens.find();
meteor:PRIMARY>
But I get no tokens.
UPDATE 2
I haven't been able to fix the bug. Is there any simple (or complex) Meteor apps on github (or somewhere else) which have Apple push notifications and which I could clone and thus find the solutions.
Its quite likely that the token is saving but the way you're looking at it makes it appear as if its not, because it may not be visible at the places you're looking at the instant its being looked at.
Keep in mind that :
Meteor doesn't publish all data to the client unless autopublish is in to your project.
If you insert something on the server, it is not immediately available on the client, in the case that it is published to the client
The way that you look for the tokens is right after you call Meteor.call, it's not very likely the data would have been received on the client at this point.
I'm not sure whether this would make any difference, but you're using asynchronous javascript on the server. Meteor uses fibers and you don't have to do this.
It's helpful in that, if there is a problem meteor will throw an error. You can simply do this:
if (Meteor.isServer) {
Tokens.insert({token: myToken});
console.log("Token is now saved!");
}
To check whether the token has been inserted, the best way is to use the meteor mongo console while your app is running and check whether the tokens are in there, this is the actual mongo shell to the database so meteor's publish delay/lack of publish method is likely not to be an issue.
meteor mongo
>db.tokens.find();
(If your collection is called 'tokens', ie : var PushTokens = new Mongo.Collection("tokens").
Related
I am encountering a weird issue here...
After I seem to successfully insert some data into my db.collection I cant seem to get it to reflect using db.collection.find().fetch().
Find below the code I insert into my chrome console:
merchantReviews.insert({merchantScore: "5.5"}, function() {
console.log("Review value successfully inserted");
});
This yields:
"9sd5787kj7dsd98ycnd"
Review value successfully inserted
I think returned value "9sd5787kj7dsd98ycnd" is an indication of a successful db collection insert. Then when I run:
merchantReviews.find().fetch()
I get:
[]
Can anyone tell me what is going on here?
Looking forward to your help.
There are two possibilities here: either the insert fails on the server even though it passes on the client, or you haven't subscribed to your collection.
In case the insert fails on server (most likely due to insufficient permissions, if you have removed the insecure package but have not declared any collection.allow rules), the client code still returns the intended insert ID (in your case, "9sd5787kj7dsd98ycnd"). The callback is called once the server has confirmed that the insert has either failed or succeeded. If it has failed, the callback is called with a single error argument. To catch this, you can instead insert the document like this:
merchantReviews.insert({merchantScore: "5.5"}, function(error) {
if (error) {
console.error(error);
} else {
console.log("Review value successfully inserted");
}
});
If this still logs successful insert, then you haven't subscribed to the collection, and you have removed the autopublish package. You can read about Meteor publish-subscribe system here. Basically, you have to publish the collection in server-side code:
Meteor.publish('reviews', function () {
return merchantReviews.find();
});
And in server code (or your js console) you need to subscribe to the collection with Meteor.subscribe('reviews'). Now calling merchantReviews.find().fetch() should return all documents in the collection.
I have written the following code in my client side js:
var resolutionsQ;
Template.body.onCreated(function bodyOnCreated() {
resolutionsQ = new Mongo.Collection("res");
});
Template.body.helpers({
resolutions: function() {
var res = resolutionsQ.find({});
console.log(res);
return resolutionsQ.find({});
}
});
Then in my project folder(in terminal), i wrote:
meteor mongo
After the mongo db console started, I worte:
db.res.insert({title: "hello #1", createdAt: new Date()});
This also worked.
When I wrote this, my frontend application showed everything as expected. Then I shut down my computer, and after sometime switched it on again and tried to run my meteor application. Now I see nothing, I get no error either in server console or browser's console. I don't know what went wrong then.
Please help.
You've created a client-side collection by defining the collection only in client code. A collection needs to be defined on both the server and the client in order to persist documents to the database.
The quick solution is to create a shared file like lib/collections/resolutions.js which will contain:
Resolutions = new Mongo.Collection("resolutions");
Using the new-style imports mechanism, you would create a file like imports/api/resolutions/resolutions.js which will contain:
import { Mongo } from 'meteor/mongo';
export const Todos = new TodosCollection('Todos');
See this section of the guide for more details.
I am using pouchdb at client side(ionic mobile app) couchdb at server side.
I need to perform operation after pouchdb successfully created and sync with couchdb.
so how can I wait till pouchdb complete initial activity.then after only my client side execution should start.
currently pouch is working on asynchronous manner so sometime before pouch initialize my application starts execution and I am getting error for pouchdb.
When working with asynchronous functions such as waiting for a respone from a server in JavaScript you use promises or callbacks to wait for an answer.
from the pouchdb docs we can read that they provide a fully asynchronous API.
Callback version:
db.get('mittens', function (error, doc) {
if (error) {
// oh noes! we got an error
} else {
// okay, doc contains our document
}
});
Promise version:
db.get('mittens').then(function (doc) {
// okay, doc contains our document
}).catch(function (err) {
// oh noes! we got an error
});
I have a User controller that has a create method that checks the database for email and username uniqueness before creating the user (this is to work-around a bug in the mongodb adpater for SailsJS that doesn't honour the unique attribute flag - version 0.10.5).
The code looks like the following:
User.find({ email: req.body.email }, function (err, user) {
if(user) {
return res.badRequest('Unique email constraint. Email is already used.');
}
});
User.create(req.body).exec(function (err, user) {
// Code to catch and manage err or new user
}
What I expect is that if the email already exists in the database (mongodb), to send a 400 using res.badRequest(), then execution to end.
What happens is that the response is sent, but then control moves to User.create() - execution doesn't end. I suspect that return res.badRequest is returning control back to the calling function (User.findOne), and execution continues from there.
I tried using res.badRequest().end() but that leaves the client hanging (there is no response), and using res.end() after the return res.badRequest() generated 'header send' errors.
How do I have execution of this request end if an existing email is found?
First of all, your findOne is here a find. That's not related to your problem, but it is slightly confusing, and you should ensure you are getting data in the format you expect.
As for finishing the request after marking it bad, I have not used sails, but I was able to end execution in the past by using res.send(). EDIT: after looking at the docs, it seems this is done for you by .badRequest(), so ignore that part.
That said, even THAT is not actually your problem. Your problem is that you start an asynchronous User.find(), and then you immediately start running User.create() (also asynchronously), and so your request doesn't get marked bad until after you have already attempted to create a new user.
What you need to do is one of two things:
Use promises (NOTE: this is how it works for Mongoose; Sails may be different) to only run User.create() after User.find() has completed. e.g;
var userQuery = User.findOne({ email: req.body.email }).exec();
userQuery.addBack(function(err, user) {
if(!!user) res.badRequest('...');
else create_user();
});
Put your user creation logic inside of your findOne block. e.g.;
User.findOne({ email: req.body.email }, function(err, user) {
if (user) { // or perhaps you want if (!err)
User.create(...);
} else {
// handle error
}
});
Personally, I would advise that you use promises (especially later, when you have long chains of requests happening one on top of the other), but take your pick.
I'm working on a website using nodejs for server side, emberjs for client side and mongodb for database. I have a page where a user profile is created and saved but the id of the data is stored as undefined unless I refresh. Is there a way atound this?
I would have to see the specific code in order to answer this with certain, but I suspect that you're either not waiting for a response from the server, or you're not passing in the model when you transition to the new route. Ember-data automatically updates when it gets a response from the server.
The general flow should go like this:
Send your post request to the server.
The server creates the user in Mongodb, and when it gets that object back, it sends it back to the client.
On the client, you wait to get the user back from the server, and pass the model into your transitionTo helper.
Here's an example on the Ember side:
App.UserCreateController = Ember.ObjectController.extend({
actions: {
createUser: function() {
var self = this;
this.get('model')
.save()
.then(function() {
self.transitionToRoute('profile', self.get('model'));
}, function() {
alert('User not successfully saved');
});
}
}
});
Another possible issue is that you're not sending the data back as Ember-data expects. i.e. Your payload should look something like this:
{
user: {
_id: 'lkj234l23jlk5j4l32j5lk34',
name: 'Jon Snow'
}
}
And you should let Ember know that it should be using the _id instead:
App.ApplicationSerializer = DS.RESTSerializer.extend({
primaryKey: "_id"
});
If this isn't your problem, post some code or give more details.