How to wait till PouchDB successfully connects - ionic-framework

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
});

Related

Extremely high loading times - Requests not running async. Mongoose

Overview
I've built an application with Vue, Express and MongoDB (mongoose ORM).
On loading the landing page, a series of GET requests are made for various bits of data. The loading times are extremely high, I've recorded some times as high as 22s for a particular route. It's lead me to believe that my requests are running sequentially, despite specifying in my logic that everything should run async
I've tried reducing the size of the objects being returned from the requests as well as using the .lean() method. These attempts shaved off a couple of seconds, but the overall issue is not remotely sorted. Times are still stupid high. To give an example:
From This:
// Method to find all users
var users = await User.find({});
To:
// Method to find all users
var users = await User.find({}, "username, uid").lean();
On the page in question, there are about 5 main components. Each component is making a get request. One of these is a Chat Column and the code for it is as follows:
ChatCol.vue
beforeMount () {
this.$store.dispatch('retrieve_chat')
}
Store.js (am using Vuex store)
retrieve_chat (context) {
return new Promise((resolve, reject) => {
axios({
url: api.dev + 'api/v1/chat',
method: 'GET',
})
.then(res => {
context.commit('set_chat', res.data)
resolve(res);
}).catch(err => {
// alert(err)
reject(err);
})
})
},
Requests in this format are being made on all the components. About 5 of them in the page in question.
Backend / Server Code
To give some context into the requests being made.
The client will hit the route 'http://localhost:3000/api/v1/chat'
and the code that makes the request on the server is the following:
var Chat = require("../models/ChatMessage");
module.exports = {
// LIMIT CHAT TO 100 MESSAGES
async get_chat(req, res) {
Chat.find({}, function(err, messages) {
if (err) {
return res.status(500).send({
message: "Interval Server Error",
type: "MONGO_CHAT_DOCUMENT_QUERY",
err: err,
})
}
if (!messages) {
return res.status(400).send({
message: "Resource not found",
type: "MONGO_CHAT_DOCUMENT_QUERY",
details: "!messages - no messages found",
})
}
messages.reverse();
return res.status(200).json({
messages,
});
}).sort({"_id": -1}).limit(30);
},
}
If I look at the network tab on the chrome dev tools, this is how the requests appear. Apologies for the long winded post, I literally have no idea what is causing this
Important Note:
It was mentioned to me that mongodb has this feature where it locks when mutating the data, and I thought that might be the case, but there are no mutations taking place. It's just 3/4 get requests happening in parallel, albeit pretty big requests, but they shouldn't be taking as long as they are
Screenshot of the network tab:
(ignore the failed req, and some of the duplicate named requests)
StackOverflow sempais please help. It's a very big application and I don't know what the issue is exactly, so If I've missed out any details - Apologies, I'll clarify anything that needs clarity.
Large amount of base64 encoded data from a previously abandoned and poorly implemented image upload feature was being stored in each chat message as well as other places, causing large amounts of data to be loaded in and ultimately lead to huge loading times.
Thank you Neil Lunn.

self.addEventListener('fetch', function(e) { }) is not working

I have a doubt in PWA and will be glad if someone helps me with that. In my PWA I don't have any problem with storing static files like HTML, JS & CSS. But am facing Issues on dynamic data. i.e : my self.addEventListener('fetch', function(e) { }) is not getting called, but other functionalities are working fine i.e: 'install' and 'active' event.
to be more particular, I am using #angular/service-worker which worked fine but I created another sw file called sw.js. In my sw-js I'm listening to the events like 'install' 'active' and 'fetch'. My sw.js fetch is not getting called whereas the other two methods work well. But while fetching the ngsw-worker.js's fetch method alone gets called.
The thing I need is to make CRUD Operations in PWA with angular.
Thanks in advance!
You can do the dynamic caching like below , the service worker will intercept every request and add in to the cache.
self.addEventListener("fetch", function (event) {
event.respondWith(
caches.open("dynamiccache").then(function (cache) {
return fetch(event.request).then(function (res) {
cache.put(event.request, res.clone());
return res;
})
})
)
}
Note : You can't cache POST Requests
Can service workers cache POST requests?

[ 'Parse error: Can\'t wait without a fiber' ]' When trying to do find within Metor

When receiving JSON data via websockets, I'm trying to feed this data into a mongodb within meteor. I'm getting the JSON data fine, but when trying to find whether the data already exists in the database, I keep getting the error: "[ 'Parse error: Can\'t wait without a fiber' ]'.
binance.websockets.miniTicker(markets => {
//we've got the live information from binance
if (db.Coins.find({}).count() === 0) {
//if there's nothing in the database right now
markets.forEach(function(coin) {
//for each coin in the JSON file, create a new document
db.Coins.insert(coin);
});
}
});
Can anyone point me in the right direction to get this cleared up?
Many thanks,
Rufus
You execute a mongo operation within an async function's callback. This callback is not bound to the running fiber anymore. In order to connect the callback to a fiber you need to use Meteor.bindEnvironment which binds the fiber to the callback.
binance.websockets.miniTicker(Meteor.bindEnvironment((markets) => {
//we've got the live information from binance
if (db.Coins.find({}).count() === 0) {
//if there's nothing in the database right now
markets.forEach(function(coin) {
//for each coin in the JSON file, create a new document
db.Coins.insert(coin);
});
}
}));
You should not require to bind to the function within the forEach as they are not async.
Related posts on SO:
Meteor.Collection with Meteor.bindEnvironment
Meteor: Calling an asynchronous function inside a Meteor.method and returning the result
Meteor wrapAsync or bindEnvironment without standard callback signature
What's going on with Meteor and Fibers/bindEnvironment()?

Meteor.methods fails on the server side

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").

How to wait on the client side until connection to mongo on the server side is ready?

I have a kind of slow connection between my meteor server and remote mongodb instance. Can I somehow wait on a client side and not register subscriptions until the server is not established connection to mongo?
One primitive way of doing this is listening for a change in Meteor.userId() using Meteor.autorun. If you are able to get this, you would know that you have connected to MongoDB. If you are not dealing with authentication, then you could create a method on the server side which returns something from MongoDB. When it returns something, on success in the client side you could start all of the subscriptions.
The most reliable way of doing this is via a Meteor.call invocation. If you do this as a synchronous call (no callback), the client will wait until the call completes. Here's how to do it asynchronously:
Meteor.call('isEverythingReady', param1,
function(error, result) {
if (error === undefined) {
Meteor.subscribe("mystuff");
Session.set("sess1", "whatever");
} else {
alert("There was an error during startup.");
}
});
and then
if (Meteor.isServer) {
Meteor.methods( {
isEverythingReady: function(param1) {
// can you connect to database?
return true;
}
}
}