Meteor observe changes added callback - meteor

#DavidWeldon I tried your code (Meteor observe changes added callback on server fires on all item) and it's very good thank you !
However I would like to have your advise : I use it for desktop notifications : when i get one notification, there is one console log (ok), but when i get another notification (total : 2), there are two console log (I want only one console log because there is only a +1 notification)
Here is my code :
if (Notification.permission !== "granted")
Notification.requestPermission();
var query = Notifications.find({userId: Meteor.userId(), read: false});
(function() {
var initializing = true;
query.observeChanges({
added: function(id, notification) {
if (!initializing) {
console.log(notification);
}
}
});
initializing = false;
})();
Thank you for your help ! :)

You could use another flag in there?
if (Notification.permission !== "granted")
Notification.requestPermission();
var query = Notifications.find({userId: Meteor.userId(), read: false});
(function() {
var initializing = true;
var firstNotif = true;
query.observeChanges({
added: function(id, notification) {
if (!initializing && firstNotif) {
firstNotif = false;
console.log(notification);
}
}
});
initializing = false;
})();

Finally I found an answer, exploring this post in discover meteor : https://www.discovermeteor.com/blog/template-level-subscriptions/
(in my question, I was working in Template.notifications.helpers)
Here's my new code :
Template.notifications.onCreated(function () {
if (Notification.permission !== "granted")
Notification.requestPermission();
var instance = this;
instance.autorun(function () {
var query = Notifications.find({userId: Meteor.userId(), read: false});
query.observeChanges({
added: function(id, notification) {
var notification = new Notification('Notification', {
icon: '',
body: "You got a new notification !"
});
}
});
});
});

Related

web push notification - getting same notifications multiple times on chrome

I'm working on push notification. I'm facing the issue of getting same notification multiple time even I have written code for closing notification.
self.addEventListener('push', async (event) => {
if (event.data) {
const [data] = event.data.json()
const body = `Notification: ${data.timestampV} - ${data.eventType}`
const title = 'Web Notification'
const options = {
body,
icon: 'images/icon.png',
badge: 'images/badge.png',
}
event.waitUntil(self.registration.showNotification(title, options))
} else {
console.log('This push event has no data.')
}
})
self.addEventListener('notificationclick', function (event) {
event.notification.close()
// close all notifications
self.registration.getNotifications().then(function (notifications) {
notifications.forEach(function (notification) {
notification.close();
});
});
// eslint-disable-next-line no-undef
clients.openWindow('/feeds')
})
Thanks in advance.
This code works for me.
Add async function
var newEvent = new Event('push');
newEvent.waitUntil = e.waitUntil.bind(e);
newEvent.data = {
json: async function () {
var newData = e.data.json();
newData.notification = newData.data;
self.registration.showNotification(newData.data.title, {
...newData.data,
data: newData.data
});
return newData;
},
};
please check it from
https://github.com/firebase/quickstart-js/issues/71#issuecomment-396958853

Meteor userId is always null

This Meteor app has the insecure and autopublish removed and accounts-password added.
meteor:PRIMARY> db.users.find({}); also shows the presence of the only user credentials I used.
Invoking Meteor.call('addTasks1',params); throws the error, further checks show Meteor.userId() being null
Why is that and how to fix it? Thanks
update
As per the suggested fix by Stephen Woods;
When I change the method addTasks1 on the server from Meteor.userId() to this.userId, It still throws the error.
///////////////////////////
// both/both.js //
///////////////////////////
Tasks1 = new Mongo.Collection('tasks1');
///////////////////////////
// client/client.js //
///////////////////////////
Template.login.events({
'click #logMe': function() {
var credentials = [$('#id').val(), $('#pin').val()];
Meteor.call('logMeIn', credentials);
}
});
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);
}
}
}
});
///////////////////////////
// server/server.js //
///////////////////////////
Meteor.methods({
logMeIn: function (credentials) {
Accounts.createUser({username: credentials[0], password: credentials[1]});
}
});
Meteor.publish('tasks1', function(){
return Tasks1.find({userId: this.userId});
});
Meteor.methods({
addTasks1: function (doc) {
if (Meteor.userId()) {
Tasks1.insert(doc);
} else {
throw new Meteor.Error("Not Authorized");
}
}
});
You need to log the user in, use Meteor.loginWithPassword(<USERNAME>, <PASSWORD>) on the client side to log a created user in.
Also, addTasks1, your Meteor method, is executing on the server. You want to use this.userId instead of Meteor.userId() on the server.

Update dynamic data in service-worker.js

I have the below data coming in form of array from a url.
[{"title":"hey hi","body":"hello","url":"https://simple-push-demo.appspot.com/","tag":"new"}]
service-worker.js
it has the above url in fetch()
'use strict';
console.log('Started', self);
self.addEventListener('install', function(event) {
self.skipWaiting();
console.log('Installed new', event);
});
self.addEventListener('activate', function(event) {
console.log('Activatednew', event);
});
self.addEventListener('push', function(event) {
try{
console.log('Push message', event);
var ev = event;
//sample
return fetch("http://localhost/push-notifications-master/app/json.php").then(function(ev,response) {
response = JSON.parse(JSON.stringify(response));
return response;
}).then(function(ev,j) {
// Yay, `j` is a JavaScript object
console.log("j", j);
for(var i in j) {
var _title = j[i].title;
var _body = j[i].body;
var _tag = j[i].tag;
console.log("_body", _body);
}
ev.waitUntil(
self.registration.showNotification("push title", {
body: _body,
icon: 'images/icon.png',
tag: _tag
}));
});
return Promise.all(response);
}
catch(e){console.log("e", e)}
});
I am trying to see the above array data coming from that particular url in console.log("j",j);. but it shows undefined. How can i get dymanic data in sw.js Please Guide.
In your addEventListener('push' .... method, I think it might be better to wait for a response before parsing it.
Also, to be checked, but your php request should be in https (not checked by myself, but my request are on https).
Here how I do this :
event.waitUntil(
fetch('YOUR PHP URL').then(function(response) {
if (response.status !== 200) {
console.log('Problem. Status Code: ' + response.status);
throw new Error();
}
// Examine the text in the response
return response.json().then(function(data) {
if (data.error || !data.notification) {
console.error('The API returned an error.', data.error);
throw new Error();
}
var title = data.notification[0].title;
var body = data.notification[0].body;
var icon = data.notification[0].icon;
var notificationTag = data.notification[0].tag;
return self.registration.showNotification(title, {body: body,icon:icon, tag: notificationTag});
});
})
);
The json :
{"notification" : [{"title":"TITLE","body":"BODY","icon":"URL TO ICON","tag":"TAG"}]}
Hope it can be useful.

Meteor. Problems with subscribe/publish

i have a problem.
I'm trying to build highcharts graphic.
How it works:
I'm going to my route ('ship.details'), and here i have not problems.
My problem:
subsription to (ships_snapshots_all) not working.
My publish.js:
Meteor.publish("ships_snapshots", function(user, options) {
if(!this.userId) return null;
if(this.userId) {
console.log('subsribed by ' + user);
return ships_snapshots.find({userId: user}, options);
}
});
Meteor.publish("ships_snapshots_all", function() {
return ships_snapshots.find({});
})
My subscribe.js (in lib folder):
Meteor.subscribe('ships_snapshots');
Meteor.subscribe('ships_snapshots_all');
Problem 100% in my subsription, because if i'm installing autopublish all working good. And problem in my router i think.
router.js:
Router.route('/ships/details', {
name: 'ship.details',
loadingTemplate: 'loading',
onBeforeAction: function() {
var shipId = Session.get('currentShipId');
if(!shipId) {
Router.go('user.ships');
} else {
this.next();
}
},
waitOn: function() {
if (Meteor.isClient) {
var getCompare = Meteor.user().profile.wows.compareWith;
console.log(getCompare);
var user2 = Meteor.users.findOne({"profile.wows.nickname": getCompare});
var user2Id = user2._id;
if (getCompare) {
var user2 = Meteor.users.findOne({"profile.wows.nickname": getCompare});
if (user2) {
var user2Id = user2._id;
}
}
if (getCompare) {
var handle = Meteor.subscribe('ships_snapshots', Meteor.user()._id) && Meteor.subscribe('ships_snapshots', user2Id) && Meteor.subscribe('userSearchInfo', getCompare);
Session.set('compareWith', user2);
console.log('user2 _____');
console.log(user2);
return handle
} else {
var handle = Meteor.subscribe('ships_snapshots', Meteor.user()._id) && Meteor.subscribe('ships_snapshots', user2Id);
return handle
}
}, data: function() {
if (handle.ready()) {
var shipname = this.params.shipName;
var obj = {};
var query = ships.findOne();
var shipId = Session.get('currentShipId');
var result;
_.each(Meteor.user().profile.wows.ships, function(row) {
if (row.ship_id === shipId) {
result = row;
}
});
return result;
}
}
});
I think my problem in subscripion for ship_snapshots. Something going wrong here, but i can't to resolve this problem.
What exactly do you mean by "not working"? From your code I would assume that you're always seeing all the ship snapshots.
You shouldn't have the subscribes in /lib if you have them in your router. If you have Meteor.subscribe('ships_snapshots_all'); in /lib then you should always be seeing all the ship snapshots (assuming you're not stopping that subscription anywhere).
Also your subscription to all should be:
Meteor.publish("ships_snapshots", function(user, options) {
if(this.userId) {
console.log('subsribed by ' + user);
return ships_snapshots.find({userId: user}, options);
} else this.ready();
});
You don't want to return null when there is no user, you can just mark the subscription as ready without finding any records. This is not the cause of your problem but just good practice.
Meteor.publish("ships_snapshots", function(user, options) {
if(!this.userId) return null;
if(this.userId) {
console.log('subsribed by ' + user);
return ships_snapshots.find({userId: user._id}, options);
}
});
In your publish script, is user really an id or is it a user object? I changed it to user._id. Please check that.

how to push data back to client in meteor?

I have to make a aggregate query to DB when the user click on a button, however I don't know how to return that result back to the client since I'm doing an asynchronous request, this is part of my code:
//Server side
Meteor.startup(function() {
Meteor.methods({
getAllTotals: function (query){
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var error = result = match = pipeline = '';
var group = {
$group: {
_id: null,
wall_clock: {
"$sum": "$wall_clock"
},
mem:{
"$sum": "$mem"
},
cpu:{
"$sum": "$cpu"
},
io:{
"$sum": "$io"
},
vmem:{
"$sum": "$vmem"
},
maxvmem:{
"$sum": "maxvmem"
}
}
};
if(typeof query.submission_time !== "undefined"){
match = {"$match": {submission_time: query.submission_time}};
pipeline = [match, group];
}else{
pipeline = [group];
}
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
Meteor.bindEnvironment(
function (error, result){
console.log(result); // <<--- this is OK!
},
function(error) {
Meteor._debug( "Error doing aggregation: " + error);
}
)
);
return result; // <<--- this is empty
}
});
}
any suggestion? :-)
Short answer:
Solution you can find here:
How to get an async data in a function with Meteor
Detailed answer
using Meteor._wrapAsync
var aggregateTotal = function(callback){
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
// ...
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
function (error, result){
if(error){
callback(error);
}else{
callback(null, result);
}
}
);
}
var aggregateTotalsSync = Meteor._wrapAsync(aggregateTotal);
Meteor.methods({
'getAllTotals': function(){
var result;
try{
result = aggregateTotalsSync();
}catch(e){
console.log("getAllTotals method returned error : " + e);
}finally{
return result;
}
}
});
using Futures (meteorPad example)
//Server side
Meteor.startup(function() {
var Future = Npm.require('fibers/future');
Meteor.methods({
getAllTotals: function (query){
var fut = new Future();
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
// ...
db.collection("GE_qstat_job_monitor").aggregate(
pipeline,
Meteor.bindEnvironment(
function (error, result){
if(error){
fut.throw(error);
}else{
fut.return(result)
}
},
function (exception){
// caught exception is passed to this callback
fut.throw(exception);
}
)
);
return fut.wait();
}
});
}
Easy but a bit dirty way (but not so much if you think well about your architecture) -> send back the result trough Mongo.
You can even do it without Meteor.methods, with the request creation inserted in the database on the client, an observer on the server that check it and does the async task, and then write back the result in the database.

Resources