why client.smembers is not returning any members? - node.js

im currently working on a chat application for the backend.here once we do /chat we are shown our friend list, from which we can start a conversation with anyone.in order to display the list of friends, i used smembers but its not returning any members even when i have friends added to my account.
app.get('/chat', utils.restrict, function(req,res){
client.smembers('appname:users' + req.user.id + ':friends', function(err, members) {
if (members && members.length > 0) {
res.render('chat', {user: req.user, users : members});
}
else{
res.send("No Friends Found!");
}
});
});
when i debug this, i see that the client.smembers line of code is hit but after that the value of members is given 0.i have required all of these too:
var app = module.parent.exports.app
, ACS = module.parent.exports.acs
, client = module.parent.exports.client
, passport = require('passport')
, config = require('../config')
, utils = module.parent.exports.utils;
what am i doing wrong?

At last, after spending a lot of time i found out that the problem was with the database instance i was querying.I created a new instance of redis which did not have the data i wanted. i used redis-cli which is the command line interface utility to talk with Redis.

Related

Get friend suggestions from users contacts based on whether the contact number is associated with any given account

I am trying to build an expo app with firebase auth and an express backend.
I want to build a friend suggestion system from contacts like in snapchat and instagram and other social media.
I am requesting the users for contacts permission and then processing that array just to get the phone numbers and match the format needed by firebase then I match the numbers with
However, if the contact list is too large then the request takes very long to complete (about 30s).
I understand that all contacts must be checked but how do big social medias reduce the time taken to check contacts by so much.
Server code:
//firebase admin function
const phoneNumberExists = async (phoneNumber: string) =>
await getAuth(admin).getUserByPhoneNumber(phoneNumber);
const getUsersByContacts = async (
//array of contact numbers as a string because some might include the country code
contacts: string[],
//current user's uid
currUid: string
) => {
const users = [];
for await (let contact of contacts) {
try {
//formats string according to indian phone numbers and adds country code
contact = contact.trim().replace(/ /g, "");
if (contact.length !== 13 || !contact.startsWith("+")) {
if (contact.length === 10) contact = "+91" + contact;
else if (contact.length === 12) contact = "+" + contact;
}
const { uid } = await phoneNumberExists(contact);
//checks whether mobile number belongs to current user
if (currUid !== uid) {
// gets properties of the user based on uid
const actualUser = await getUserData(uid);
if (actualUser) users.push(actualUser);
}
} catch (error) {
// this error code means no user found with the phone number so I continue
if (error.code === "auth/user-not-found") continue;
}
}
return users;
};
Every contact has to be checked and since it's the firebase function which is causing the delay I was wondering if there was a way to this with node js duplex stream. I haven't worked with streams in the past but from what I read about streams they fit the need. However all examples of streams are related to file streaming.
Is it possible to send contacts as a stream and get suggestions as a stream.
Should I convert the contacts array into a file first and then stream it?

Using wildcards in firestore get query

I want to create a cloud function in firebase that gets triggered whenever a user logs in for the first time. The function needs to add the UID from the authentication of the specific user to a specific, already existing document in firestore. The problem is that the UID needs to be added to a document of which I do not know the location. The code I have right now doesn't completely do that, but this is the part where it goes wrong. The database looks like this when simplified
organisations
[randomly generated id]
people
[randomly generated id] (in here, a specific document needs to be found based on known email
adress)
There are multiple different organisations and it is unknown to which organisation the user belongs. I thought of using a wildcard, something like the following:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
console.log('function ready');
//Detect first login from user
//if(firebase.auth.UserCredential.isNewUser()){
if(true){
//User is logged in for the first time
//const userID = firebase.auth().currentUser.UID;
//const userEmail = firebase.auth().currentUser.email;
const userID = '1234567890';
const userEmail = 'example#example.com';
//Get email, either personal or work
console.log('Taking a snapshot...');
const snapshot = db.collection('organisations/{orgID}/people').get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log(doc.data());
});
});
}
I commented out some authentication-based lines for testing purposes. I know the code still runs, because hardcoding the orgID does return the right values. Also, looping trough every organisation is not an option, because I need to have the possibility of having a lot of organisations.
A lot of solutions are based on firestore triggers, like onWrite, where you can use wildcards like this.
However, I don't think that's possible in this case
The solution to the problem above:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
//Add UID to document in DB[FMIS-94]
//Detect first login from user
//if(firebase.auth.UserCredential.isNewUser()){
if(true){
//User is logged in for the first time
//const userID = firebase.auth().currentUser.UID;
//const userEmail = firebase.auth().currentUser.email;
const userID = '1234567890';
const userEmail = 'example#example.com';
var docFound = false;
//Get email, either personal or work
console.log('Taking a snapshot...');
//Test for work email
const snapshot = db.collectionGroup('people').where('email.work', '==', userEmail).get()
.then(function(querySnapshot){
querySnapshot.forEach(function(doc){
//work email found
console.log('work email found');
console.log(doc.data());
docFound = true;
const organisationID = doc.ref.parent.parent.id;
writeUID(doc.id, userID, organisationID);
});
});
if(!docFound){
//Test for personal email
const snapshot = db.collectionGroup('people').where('email.personal', '==', userEmail).get()
.then(function(querySnapshot){
querySnapshot.forEach(function(doc){
//personal email found
console.log('personal email found');
console.log(doc.data());
const organisationID = doc.ref.parent.parent.id;
writeUID(doc.id, userID, organisationID);
});
});
}
}
async function writeUID(doc, uid, organisationID){
const res = db.collection(`organisations/${organisationID}/people`).doc(doc).set({
userId: uid
}, { merge: true });
}
This was exactly what I needed, thanks for all your help everyone!
It is not possible to trigger a Cloud Function when a user logs in to your frontend application. There is no such trigger among the Firebase Authentication triggers.
If you want to update a document based on some characteristics of the user (uid or email), you can do that from the app, after the user has logged in.
You mention, in your question, "in here, a specific document needs to be found based on known email address". You should first build a query to find this document and then update it, all of that from the app.
Another classical approach is to create, for each user, a specific document which uses the user uid as document ID, for example in a users collection. It is then very easy to identify/find this document, since, as soon the user is logged in you know his uid.
I'm not sure I understand you correctly, but if you want to search across all people collections not matter what organizations document they're under, the solution is to use a collection group query for that.
db.collectionGroup('people').get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log("user: "+doc.id+" in organization: "+doc.ref.parent.parent.id);
});
});
This will return a snapshot across all people collections in your entire Firestore database.
First setup Cloud Functions according to the official Documentation.
Then after setting up create functions like this:
exports.YOURFUNCTIONNAME= functions.firestore
.document('organisations/[randomly generated id]/people/[randomly generated id]')
.oncreate(res => {
const data = res.data();
const email = data.email;/----Your field name goes here-----/
/-----------------Then apply your logic here---------/
)}
This will triggers the function whenever you create the People -> Random ID

Update and add new Firebase child nodes in Firebase web app at the same time

I have been able to push new information and call it on the database but I been looking for several days now and I can't seem to find anything.
I am looking to be able to update a node that already has a value and add a new node if it doesn't. Can anyone help me with this. New to Firebase.
Thanks
code:
function userProfileUpdate(users) {
newUsername = document.getElementById("newUsername");
// Profile Update.
var user = {
username : newUsername.value
};
return firebase.database().ref().update(user);
};
From your comments it seems that you want to store user information in a data structure like this:
users
uid1
userName: "Frank van Puffelen"
To add a specific user in this structure, you'd do:
function userProfileUpdate(users) {
var user = firebase.auth().currentUser;
var root = firebase.database().ref();
newUsername = document.getElementById("newUsername");
var user = {
username : newUsername.value
};
return root.child('users').child(user.uid).set(user);
};
Update
To update a specific property of a specific user:
Map<String, Object> updates = new HashMap<String,Object>();
updates.put("username", newUsername.value);
root.child('users').child(user.uid).updateChildren(user);
Or alternatively:
root.child('users').child(user.uid).child("username").setValue(newUsername.value);
Both will auto-create the location if it doesn't exist yet.
Frank your code took away the entire key but I did figure out with this
var user = firebase.auth().currentUser;
var root = firebase.database().ref();
newUsername = document.getElementById("newUsername");
firebase.database().ref('users/' + user.uid).update({
username: newUsername.value
});
Thanks Frank yours push me in the right direction.

How to store documents in an ArangoDb graph using ArangoJs?

I am using latest version of ArangoDb and ArangoJs from a nodejs application. I have got following two vertexes
users
tokens
tokens vertex contain the security tokens issues to one of the user in the users vertex. I have got an edge definition named token_belongs_to connecting tokens to users
How do I store a newly generated token belonging to an existing user using ArangoJs?
I am going to assume you are using ArangoDB 2.7 with the latest version of arangojs (4.1 at the time of this writing) as the API has changed a bit since the 3.x release of the driver.
As you don't mention using the Graph API the easiest way is to simply use the collections directly. Using the Graph API however adds benefits like orphaned edges automatically being deleted when any of their vertices are deleted.
First you need to get a reference to each collection you want to work with:
var users = db.collection('users');
var tokens = db.collection('tokens');
var edges = db.edgeCollection('token_belongs_to');
Or if you are using the Graph API:
var graph = db.graph('my_graph');
var users = graph.vertexCollection('users');
var tokens = graph.vertexCollection('tokens');
var edges = graph.edgeCollection('token_belongs_to');
In order to create a token for an existing user, you need to know the _id of the user. The _id of a document is made up of the collection name (users) and the _key of the document (e.g. 12345678).
If you don't have the _id or _key you can also look up the document by some other unique attribute. For example, if you have a unique attribute email that you know the value of, you could do this:
users.firstExample({email: 'admin#example.com'})
.then(function (doc) {
var userId = doc._id;
// more code goes here
});
Next you'll want to create the token:
tokens.save(tokenData)
.then(function (meta) {
var tokenId = meta._id;
// more code goes here
});
Once you have the userId and tokenId you can create the edge to define the relation between the two:
edges.save(edgeData, userId, tokenId)
.then(function (meta) {
var edgeId = meta._id;
// more code goes here
});
If you don't want to store any data on the edge you can substitute an empty object for edgeData or simply write it as:
edges.save({_from: userId, _to: tokenId})
.then(...);
So the full example would go something like this:
var graph = db.graph('my_graph');
var users = graph.vertexCollection('users');
var tokens = graph.vertexCollection('tokens');
var edges = graph.edgeCollection('token_belongs_to');
Promise.all([
users.firstExample({email: 'admin#example.com'}),
tokens.save(tokenData)
])
.then(function (args) {
var userId = args[0]._id; // result from first promise
var tokenId = args[1]._id; // result from second promise
return edges.save({_from: userId, _to: tokenId});
})
.then(function (meta) {
var edgeId = meta._id;
// Edge has been created
})
.catch(function (err) {
console.error('Something went wrong:', err.stack);
});
Attention - syntax changes:
Edge creation:
const { Database, CollectionType } = require('arangojs');
const db = new Database();
const collection = db.collection("collection_name");
if (!(await collection.exists())
await collection.create({ type: CollectionType.EDGE_COLLECTION });
await collection.save({_from: 'from_id', _to: 'to_id'});
https://arangodb.github.io/arangojs/7.1.0/interfaces/_collection_.edgecollection.html#create

Creating a JSON file(MongoDb Collection) of User Info for a Node.js application that uses Bcrypt and passport for login

I'll try and word this question as short and clear as possible. I have a node.js project that connects to a non local instance of MongoDB using mongoose. I have written code for a user to login using passport module. I create a JSON file as a users collection. When I go to sign in I get this error
throw "Not a valid BCrypt hash."
So If I wanted to just create a JSON file of Users to work with this how would I go about it? My end goal is to convert RDBMS to MongoDB. Just starting with the users table. I understand that if I was registering new users I could just make a function that would hash their password like
newUser.password= createHash(password)
var createHash = function(password){
return bCrypt.hashSync(password, bCrypt.genSaltSync(10), null);
}
or something along those lines. Summary: How do I make a JSON file of user info for MongoDB that'll work with bcrypt hash and passport?
var fs = require('fs');
var bc = require('bcrypt-nodejs')
fs.readFile('users.txt',function(err,data){
var x = [];
if(err) throw err;
var buf = new Buffer(data);
x = buf.toString();
x = JSON.parse(x);
//console.log(x);
for(var a in x){
x[a].password=createHash(x[a].password);
}
x = JSON.stringify(x);
fs.writeFile('users.txt',x,callback()); //or just push directly to db?
});
var createHash = function(password){
return bc.hashSync(password, bc.genSaltSync(10), null);
}
function callback(){
console.log('finished');
}
Just read in my User Info , Bcrypted the passwords and made a new file. Put it in Mongo. Hopefully this helps someone else. If anyone has a better solution for me I'd appreciate it.

Resources