Time delay in child_added listener - javascript

I want to add a new team member if team member not exists in the Firebase database. However I see a time delay while reading the existing entries. The below code returns null for the variable teammembertKey. Therefore I see a new key in database every time I re-login into the system. Can someone help me to solve this issue?
checkIfUserExists = function (teammemberData) {
return firebase.database().ref().child('/leaders/' + firebase.auth().currentUser.uid)
.once("value", function (snapshot) {
console.log(snapshot.exists());
return Promise.resolve({
teammemberData,
userExists: snapshot.exists(),
});
});
};
$scope.submit = function () {
var teammembertKey = null;
// A teammember entry.
// A teammember entry.
var teammemberData = {
uid: firebase.auth().currentUser.uid,
email: firebase.auth().currentUser.email,
displayName: firebase.auth().currentUser.displayName,
photoURL: firebase.auth().currentUser.photoURL
};
const p = checkIfUserExists(teammemberData);
p.then((snapshot, userExists) => {
if (userExists) {
teammembertKey = snapshot.key;
// update user
} else {
// go create a user
console.log('i');
}
})
.catch(err => {
console.warn('Error signing in.', err);
});
if (teammembertKey == null) {
// Get a key for a new team member.
teammembertKey = firebase.auth().currentUser.uid; //firebase.database().ref().push().key;
// Write the new member's data simultaneously.
var updates = {};
updates['/leaders/' + teammembertKey] = teammemberData;
const promise = firebase.database().ref().update(updates);
promise
.then(e => { })
.catch(e => {
console.log(e);
})
}
};

Here is what you need.
$scope.submit = function () {
var teammembertKey = firebase.auth().currentUser.uid;
var teammemberData = {
uid: firebase.auth().currentUser.uid,
email: firebase.auth().currentUser.email,
displayName: firebase.auth().currentUser.displayName,
photoURL: firebase.auth().currentUser.photoURL
};
firebase.database().ref().child('/leaders/' + teammembertKey).once("value")
.then(funciton(snap) {
if(!snap.val()) {
var updates = {};
updates['/leaders/' + teammembertKey] = teammemberData;
const promise = firebase.database().ref().update(updates);
promise
.then(e => { })
.catch(e => {
console.log(e);
})
}
})
.catch(err => {
console.warn('Error signing in.', err);
});
};

Related

How to emit events from BullMQ queue to only the user that is the owner of the job

My usecase of socket is not for chats, it's specifically to tell the front-end what BullMQ queue events happened, with a progress bar and telling when a job is done or failed.
Currently when I'm emitting events, it's going for all users, I tried to use the socket.to(socket.id).emit({ myEvent: example }) but didn't work at all.
I'm storing session on Redis.
Socket
this.redisClient = new Redis(`${process.env.REDIS_URL}`);
this.sessionStore = new RedisSessionStore(this.redisClient);
this.pubClient = this.redisClient;
this.subClient = this.pubClient.duplicate();
this.instance.adapter(createAdapter(this.pubClient, this.subClient));
} catch (err) {
console.log("Error on Socket Controller: ", err.message);
}
this.instance.use(async (socket, next) => {
const sessionID = socket.handshake.auth.sessionID;
if (sessionID) {
const session = await this.sessionStore.findSession(sessionID);
if (session) {
socket.sessionID = sessionID;
socket.userID = session.userID;
socket.username = session.username;
return next();
}
}
const username = socket.handshake.auth.username;
if (!username) {
return next(new Error("invalid username"));
}
socket.sessionID = uuidv4();
socket.userID = uuidv4();
socket.username = username;
console.log(socket.sessionID, socket.userID, socket.username);
next();
});
this.instance.on("connection", async (socket) => {
// Assign socket to the class
this.socket = this.socket == null ? socket : this.socket;
let connectedUsersCount =
Object.keys(this.instance.sockets.sockets).length + 1;
let oneUserLeft = connectedUsersCount - 1;
console.log(`New client connected`, connectedUsersCount);
try {
this.sessionStore.saveSession(this.socket.sessionID, {
userID: this.socket.userID,
username: this.socket.username,
connected: true
});
// emit session details
this.socket.emit("session", {
sessionID: this.socket.sessionID,
userID: this.socket.userID
});
// join the "userID" room
this.socket.join(this.socket.userID);
const users = [];
const sessions = await this.sessionStore.findAllSessions();
sessions.forEach((session) => {
users.push({
userID: session.userID,
username: session.username,
connected: session.connected
});
});
this.socket.emit("users", users);
// notify existing users
this.socket.broadcast.emit("user connected", {
userID: this.socket.userID,
username: this.socket.username,
connected: true,
messages: []
});
integrationQueueEvents.on("progress", async (job: any) => {
try {
console.log("Job Progressing", job);
const payload = {
status: true,
data: job.data,
jobId: job.jobId,
to: this.socket.userID
};
console.log("integration progress payload: ", payload);
this.socket.emit("integrationProgress", payload);
} catch (error) {
console.log(error);
}
// this.socket.to(this.socket.id).emit("integrationProgress", payload);
});
Session Store
findSession(id) {
return this.redisClient
.hmget(`session:${id}`, "userID", "username", "connected")
.then(mapSession);
}
saveSession(id, { userID, username, connected }) {
this.redisClient
.multi()
.hset(
`session:${id}`,
"userID",
userID,
"username",
username,
"connected",
connected
)
.expire(`session:${id}`, SESSION_TTL)
.exec();
}
async findAllSessions() {
const keys = new Set();
let nextIndex = 0;
do {
const [nextIndexAsStr, results] = await this.redisClient.scan(
nextIndex,
"MATCH",
"session:*",
"COUNT",
"100"
);
nextIndex = parseInt(nextIndexAsStr, 10);
results.forEach((s) => keys.add(s));
} while (nextIndex !== 0);
const commands = [];
keys.forEach((key) => {
commands.push(["hmget", key, "userID", "username", "connected"]);
});
return await this.redisClient
.multi(commands)
.exec()
.then((results) => {
return results
.map(([err, session]) => (err ? undefined : mapSession(session)))
.filter((v) => !!v);
});
}

I want to know why the log array doesn't return the specified user with the given id?

app.get("/api/users/:_id/logs", (req, res) => {
const id = req.params._id;
const { from, to, limit } = req.query;
** Here I tried to search for the matched user and it works successfully: **
User.findById({ _id: id }, (err, user) => {
if (!user || err) {
res.send("Unknown User Id !!");
} else {
**Then I tried to filter the log array with date **
// const username = user.username;
let responObject = {};
if (from) {
responObject["$gte"] = new Date(from).toDateString();
}
if (to) {
responObject["$lte"] = new Date(to).toDateString();
}
let filter = {
_id: id,
};
if (from || to) {
filter.date = responObject;
}
let nonNullLimit = limit ?? 500;
**try to build the array log and return it to the user but it always be empty and never return the exercises for the user **
Exercise.find(filter)
.limit(+nonNullLimit)
.exec((err, data) => {
if (err || !data) {
res.json([]);
} else {
const count = data.length;
const rowLog = data;
const { username, _id } = user;
const log = rowLog.map((item) => ({
description: item.description,
duration: item.duration,
date: new Date(item.date).toDateString(),
}));
console.log(log)
if (from && to) {
res.json({
username,
from: new Date(from).toDateString(),
to: new Date(to).toDateString(),
count,
_id,
log,
});
} else {
res.json({
username,
count,
_id,
log,
});
}
}
});
}
});
});
this is the result when I try to log all the exercises for the user
{"username":"ahmed","count":0,"_id":"62a9aab2743ddfc9df5165f2","log":[]}

Getting a nested parameter return value in the wrapped function return

I have a scenario where I need to get the return value from a function that passed to another function as a parameter. I tried multiple ways. But couldn't get the returnValue to the CreateProfileComponent from ProfileAction.js file.
// ProfileAction.js
export default (database) => {
return {
createProfile: async (createdProfile) => {
const profileCollection = database.get("profiles");
const { name, email } = createdProfile;
try {
await database.action(async () => {
const returnValue = await profileCollection.create((profile) => {
profile.name = name;
profile.email = email;
});
});
} catch (error) {
console.log("createProfile", error);
}
},
};
};
// CreateProfileComponent.js
const CreateProfileComponent = () => {
const database = useDatabase();
const profileAction = ProfileAction(database);
const createdRecord = await profileAction.createProfile({
name: "John Doe",
email: "johndoe#gmail.com",
});
}
Finally what I want is the returnValue value in CreateProfileComponent. The functions database.actions() and profileCollection.create() are used from a third party library (WatermelonDB)
I am not sure what database.action does but you should return a value in this function. Like following: return await database.action(async () => {
And throw an error on catch
export default (database) => {
return {
createProfile: async (createdProfile) => {
const profileCollection = database.get("profiles");
const { name, email } = createdProfile;
try {
return await database.action(async () => {
const returnValue = await profileCollection.create((profile) => {
profile.name = name;
profile.email = email;
});
});
} catch (error) {
console.log("createProfile", error);
throw error;
}
},
};
};
// CreateProfileComponent.js
const CreateProfileComponent = () => {
const database = useDatabase();
const profileAction = ProfileAction(database);
try {
const createdRecord = await profileAction.createProfile({
name: "John Doe",
email: "johndoe#gmail.com",
});
} catch (e) {
}
}

Firebase Function:Function returned undefined, expected Promise or value

I have written a firebase function to send notification whenever a like occurs in my android app. The notification functionality works good most of the times but sometimes does not work.
I receive this error always ( whether it is working or not):
Function returned undefined, expected Promise or value
Here's the code of my like function:
exports.sendactorLikeNotification = functions.database.ref('/Likes/{post_id}/{user_id}')
.onWrite(event => {
if (event.data.exists())
{
const message = event.data.val();
const userUid = event.params.user_id;
const ownerUid = message.owner_id;
console.log("Owner id", ownerUid);
const userPic = message.thumb_image;
const userName = message.name;
const post_key = event.params.post_id;
const timestamp = admin.database.ServerValue.TIMESTAMP;
if(ownerUid == userUid){return null;}
const Promise1= admin.database().ref(`/notifs/${ownerUid}`).push({
thumb_image: userPic,
name: userName,
user_id: userUid,
post_id: post_key,
text: "liked your post",
type: "Like",
read: "false",
time: timestamp
});
const Promise2=admin.database().ref(`/Users/${ownerUid}/device_token`).once('value');
const Promise3= Promise2.then(function(snapshot) {
const getrealDeviceTokensPromise = snapshot.val();
console.log("Device Token", getrealDeviceTokensPromise);
// Notification details.
const payload = {
notification: {
title: 'Appname',
body: userName + ' has liked your post.',
icon: "default",
sound: "default",
click_action: "OPEN_ACTIVITY_1"
}
};
const Promise4= admin.messaging().sendToDevice(getrealDeviceTokensPromise, payload)
.then(function (response) {
console.log("Successfully sent message:", response);
return Promise.all([Promise1,Promise3,Promise4]);
})
.catch(function (error) {
console.log("Error sending message:", error);
return null;
});
}, function(error) {
// The Promise was rejected.
console.error(error);
return null;
});
}
else
{
return null;
}
});
I don't understand where I am going wrong. Please help!
exports.sendactorLikeNotification = functions.database.ref('/Likes/{post_id}/{user_id}').onWrite(event => {
if (event.data.exists()) {
const promises=[];
const message = event.data.val();
const userUid = event.params.user_id;
const ownerUid = message.owner_id;
console.log("Owner id", ownerUid);
const userPic = message.thumb_image;
const userName = message.name;
const post_key = event.params.post_id;
const timestamp = admin.database.ServerValue.TIMESTAMP;
if(ownerUid == userUid){return null;}
const a1=admin.database().ref(`/notifs/${ownerUid}`).push({
thumb_image: userPic,
name: userName,
user_id: userUid,
post_id: post_key,
text: "liked your post",
type: "Like",
read: "false",
time: timestamp
});
promises.push(a1);
const a2= admin.database().ref(`/Users/${ownerUid}/device_token`).once('value').then(function(snapshot) {
const getrealDeviceTokensPromise = snapshot.val();
console.log("Device Token", getrealDeviceTokensPromise);
// Notification details.
const payload = {
notification: {
title: 'Appname',
body: userName + ' has liked your post.',
icon: "default",
sound: "default",
click_action: "OPEN_ACTIVITY_1"
}
};
const a3=admin.messaging().sendToDevice(getrealDeviceTokensPromise, payload)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});
promises.push(a3);
}, function(error) {
console.error(error);
});
promises.push(a1);
return Promise.all(promises);
}
else
{
return null;
}
});
This code solved the problem for me!
You're returning undefined when:
event.data.exists() returns false
ownerUid == userUid
You're also not dealing with the promise returned by sendToDevice().then().catch(). The function needs to wait until that work is done before terminating.
Please test the following changes and let me know, also I recommend updating the firebase-functions SDK:
exports.sendactorLikeNotification = functions.database.ref('/Likes/{post_id}/{user_id}')
.onWrite(event => {
if (event.data.exists()) {
const promises = [];
const message = event.data.val();
const userUid = event.params.user_id;
const ownerUid = message.owner_id;
const userPic = message.thumb_image;
const userName = message.name;
const post_key = event.params.post_id;
const timestamp = admin.database.ServerValue.TIMESTAMP;
if (ownerUid === userUid) return null;
return Promise.all([admin.database().ref(`/Users/${ownerUid}/device_token`).once('value')]).then(r => {
const cO = r[0];
const aP = admin.database().ref(`/notifs/${ownerUid}`).push({
thumb_image: userPic,
name: userName,
user_id: userUid,
post_id: post_key,
text: "liked your post",
type: "Like",
read: "false",
time: timestamp
});
promises.push(aP);
const payload = {
notification: {
title: 'Appname',
body: userName + ' has liked your post.',
icon: "default",
sound: "default",
click_action: "OPEN_ACTIVITY_1"
}
};
const tokensList = Object.keys(cO.val());
promises.push(admin.messaging().sendToDevice(tokensList, payload));
return Promise.all(promises);
});
}
return null;
});

Firebase Cloud Functions with Cloud Firestore trouble

I have used this Firebase Database code in a previous project:
const getDeviceUser = admin.database().ref(`/users/${notification.to}/`).once('value');
I am now trying to convert it for Firestore. I am basically trying to get my users fcm's when a notification is being sent. I have tried many things, but haven't seen the new way to accomplish this.
EDIT: here is my code.
exports.sendFavoriteNotification = functions.firestore.document('users/{userUid}/notifications/{notificationId}').onCreate(event => {
const notification = event.data.data();
const user = event.params.userUid;
const getDeviceUser = admin.database().ref(`/users/${notification.to}/`).once('value');
// Get the follower profile.
const getProfilePromise = admin.auth().getUser(notification.sender);
return Promise.all([getDeviceUser, getProfilePromise]).then(results => {
const tokensSnapshot = results[0];
const liker = results[1];
// Check if there are any device tokens.
if (!tokensSnapshot.hasChildren()) {
return console.log('There are no notification tokens to send to.');
}
//console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.');
console.log('Fetched follower profile', liker);
// Notification details.
const payload = {
notification : {
title : 'You have a new like!',
body : `${liker.displayName} just liked your photo.`,
badge: '1',
sound: 'default'
}
};
// Listing all tokens.
var tokens = admin.firestore.ref(`/users/${notification.to}/`).get('fcm');
// Send notifications to all tokens.
admin.messaging().sendToDevice(tokens.data(), payload);
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens who are not registered anymore.
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.update({
fcm: FieldValue.delete()
}));
}
}
});
return Promise.all(tokensToRemove);
});
});
});
Hope this will help. This is my code after 2 days of trying to learn how to convert from realtime database to firestore. It is based on a firebase project: https://github.com/MahmoudAlyuDeen/FirebaseIM
let functions = require('firebase-functions');
let admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotificationToFirestone = functions.firestore.document('/notifications/{pushId}')
.onCreate(event => {
const pushId = event.data.id;
const message = event.data.data();
const senderUid = message.from;
const receiverUid = message.to;
const db = admin.firestore();
if (senderUid === receiverUid) {
console.log('pushId: '+ pushId);
return db.collection('notifications').doc(pushId).delete();;
} else {
const ref = db.collection('users').doc(receiverUid);
const query = new Promise(
function (resolve, reject) {
ref.get()
.then(doc => {
if (!doc.exists) {
console.log('No such document!');
reject(new Error('No such document!'));
} else {
console.log('Document data:', doc.data().instanceId);
resolve(doc.data().instanceId);
}
})
.catch(err => {
console.log('Error getting document', err);
reject(err);
});
});
const getSenderUidPromise = admin.auth().getUser(senderUid);
return Promise.all([query, getSenderUidPromise]).then(results => {
//console.log('instanceId = Result[0]: ' + results[0]);
//console.log('sender = Result[1]: ' + results[1]);
const instanceId = results[0];
const sender = results[1];
//console.log('notifying ' + receiverUid + ' about ' + message.body + ' from ' + senderUid);
//console.log('instanceId este' + instanceId);
const payload = {
notification: {
title: sender.displayName,
body: message.body,
icon: sender.photoURL
}
};
admin.messaging().sendToDevice(instanceId, payload)
.then(function (response) {
console.log("Message sent: ", response);
})
.catch(function (error) {
console.log("Error sending message: ", error);
});
});
}
});

Categories