Chat App - Sending multiple simultaneous requests to MongoDB - javascript

I'm building a chat app and trying to work out the most efficient way to request multiple conversation threads (both private & group) from a MongoDB database.
My current idea is to loop through the user's contacts on the client side and send a 'getConversation' request to my REST API for each contact. This happens after the user profile data has first been retrieved on the server and sent to the client, in order to populate some of the chat interface as quickly as possible, although I'm not sure if this is optimal given the number of additional requests I'm making (easily 25 - 50 at a time).
I currently think that there are 3 methods I could use:
1.) Send a request to the server for the user data > loop through each contact (private & group) on the server > get each conversation from the DB > send the entire bundle back to the client and separate data into the relevant (Vue / Vuex) modules. Total Requests: 1 / Data Requested: Large
2.) * What I'm doing now: Send an initial request for the user data > receive it on the client > loop through the contacts on the client side > send a separate API request for each contact > populate the conversations as they arrive back on the client. Total Requests: > 20 / Data Requested: Small
3.) Send the initial request for user data > receive it > send a single request for all conversations. I expect this to take longer than option 2, but I could be wrong. Total Requests: 2 / Data Requested: Medium
My objective is to retrieve both user data & conversations as quickly + as efficiently as possible, so I welcome any suggestions or techniques you've used to achieve this kind of thing.
Cheers :)
Notes:
I'm using Vue / Vuex / MongoDB / Express / SocketIO.

TL;DR I'd stay with the second option.
Since you want your app to load as fast as possible and be responsive, you should avoid requesting big chunks of data which you might even end up not using in the app. I'd fetch the first (latest) 5-10 conversations since those would probably be the ones the user would like to read first. Then, if the user wants to read more conversations you haven't fetched from the server yet, you can fetch those (and maybe some conversations from around that time). About your concern regarding sending lots of requests to the server shouldn't be significantly slower than a single big request, and it would make the app much faster and snappier.
For further discussion on this subject check out this question.

Related

How to programatically send SMS notifications to 1 million users using queues?

What we have?
An API build in Node.js (using Moleculer.js for micro-services and PostgreSQL for storing data) which has the functionality of keeping track of users and user groups. We have in average 3k users per group, and a user can be part of multiple groups.
What we want to achieve?
We want to create a special service which will send text messages. The admins will select multiple groups, the code will remove the duplicated users and send them an SMS.
After a selection we can have around 1 million users. How can we send them text messages in an efficient way?
What have we tried?
Paginate the users and for each page send a request to the SMS service.
const users = db.getPage(1); // [{ id: 1, phone: '+123456789' }, ...]
smsClient.sendBulk(users);
PROBLEM: The user list in the database can change in the process and can affect the pagination by giving us duplicates or skipping some users.
Load all the results in the memory and send all the users to the SMS service.
const users = db.getAll(); // [..., { id: 988123, phone: '+987654321' }]
smsClient.sendBulk(users);
PROBLEM: We think it's a bad idea, resource wise, to make this kind of queries to the database and keep them in the memory. In the same time, we don't want to send 1 million entities through an HTTP request to the SMS service.
How can we select a 1 million users and send them an SMS message without worry about duplicates, skipped data or any other alteration to the admin's selection? We were thinking about queues as a necessary step but after we find a solution for the cases mentioned above. Or, is the queue part of the solution?
How can we select a 1 million users and send them an SMS message without worry about duplicates, skipped data, or any other alteration to the admin's selection?
For managing duplicates You could use an additional DB to save a Hash Table for the users that been handled already. This is a bit more expensive because you will need to check the user before each SMS send.
Managing not skipping is a bit tricky because you will need to add more recipients to an ongoing SMS transaction. You will need the ability to detect (hook) when a user is added to a group and add it as recipients to the ongoing transactions accordingly.
You will need to find a fast DB and save that user in a HashSet for a fast set and get (O(1))
We were thinking about queues as a necessary step but after we find a solution for the cases mentioned above. Or, is the queue part of the solution?
Defenently. Queue is the correct way to go for this scenario (queueing many small tasks). Some queues come with a re-queue features that will re-queue any task that didn't get acknowledgment.
you need to check out RabbitMQ.message-driven microservices
Have you considered creating an indirect state between the user and sent SMS? Something like SmsRequest / SmsTask / however you'd call it.
It'd consist of necessary user-data, message content, status of the request (to-send, sending, sent, failed, ...) and some additional metadata depending on your needs.
Then the first step you'd do is to prepare these request and store them in db, effectively making a queue out of a table. You can add some constraints on user and message type that'd prevent any duplicates and then start second asynchronous process that simply fetches requests in to-send state, sets the state to sending and then saves the outcome.
This also gives you the benefit of audit + you can batch the outgoing messages and.
Of course it'd increase your data volume significantly but I guess it's cheap nowadays anyway.

Sending Message Requests

I am making a chat application using Socket.IO and Node.JS. I would like to implement message requests, such as the ones Facebook's Messenger has. I am not sure how to go about this problem.
If Mike wants to send a private message to Jake, Jake must first accept Mike's message request. Let's say Mike connects to the server using Socket.IO, and the server handles his request. Mike can then send sockets to the server, for example, a chat socket such as the one below:
socket.emit( 'chat', { // Emits the 'chat' socket to the server
name: 'Mike', // Sets the name of the sender
receiver: 'Jake', // Sets the name of the receiver
message: 'Hey Jake!' // Sets the message
} );
Now, obviously, this socket should be sent IF ANY ONLY IF Jake accepted the message request already. This is where the problem lies.
Message requests are stored in a database ( this is necessary for my application ).
I have a few ideas in mind on how to accomplish this:
Query the database each time a user sends a chat socket, to see if the receiver accepted the sender's request. Of course, this would mean that each time a chat is sent, I have a database query. This seems highly inefficient to me.
Query the database once somehow, and allow chat messages to go through without issuing a database query every time - although I am not sure how to accomplish this - hence this question.
I would love your input on this problem. Thanks!
The request you mentioned, is that request accepting should happen just once, like in facebook or it should be accepted for every message sent.
I hope it is just once, when the first message is sent. If this is the case then you can create a JSON file with an array containing Jake's friends(people accepted by Jake). Whenever someone tries to send a message to Jake, you just refer to the JSON files Jake's array to see if the sender is in the array list. If yes you can proceed with broadcasting message to Jake. If not in the array, send Jake a connection request from sender(Mike).
Since you are storing message requests in database, update the JSON file arrays when ever a new connection request is accepted by some one.
I hope this helps you. Comment below, if I am out of your scope anywhere.
There are multiple ways.
1) You can have caching done (as mentioned by #PM-77-1) which helps decrease number of database queries. Redis cache is really easy to use with Node.js. So whenever you are trying to check if Mike has Jake as a friend you can first check at cache level if Jake is in Mike's friend list. If Mike's friend list is not available you can fetch it from db once and store it in cache for future use.
2) You can also allow a user (Mike) to send around 100 to 200 short messages (just an example) and the messages are hidden for Jake until Jake accepts Mike's request. Having a limit on number of messages Mike can send without being a friend is a subjective question and it depends upon how famous application it is.

How to batch create users in Parse via REST api

I have roughly 1.5 million users I need to import into my parse _User table (we are migrating from our old sql db to Parse).
I've tried using a Background Job, but it is slow and gets killed every 15 minutes. As a result, we have only import ~300K users in 4 days.
So I decided to go the REST api route...and tried the PythonPy lib. It works, except for being able to do batch creation of users. From digging more into this, it seems that the REST api forces you to do a User.signup() call.
This of course makes the whole thing be serialized.
Is there anyway to do batch user creation?
Batch creating / signing up User objects is not supported in Parse. It is mentioned in this question:
https://parse.com/questions/what-user-operations-are-supported-in-batch

Using the Pusher.com API for client to client events

I have setup an account and app in the pusher.com API dashboard and have experimented with both private and public channels and client->client events - I have no trouble doing this.
My project is using CodeIgniter (latest) PHP framework (+ jQuery latest + pusher latest) and I have access to edit everything - nothing is out of bounds in terms of solutions, this is a non commercial project.
My aim is to have client/socket A send an event/message to client/socket B within 'channelX'.
I would like many people/sockets to be possible within 'channelX' - so for example we could have 10 clients connected to this channel, but within it I would like 2 parties to be able to communicate directly with each other (can be via server or just via pusher api).
At the moment, and where my understanding and research leads me: is that any event triggered in my 'channelX' private channel is sent to all clients - now I have used the 'exclude socket' parameter to make sure the event doesn't trigger on 'socketA' (the person doing the initiating of the event) - and this works when there is only 2 clients/sockets connected to a channel - but add more parties and it gets messy.
The question:
Should a channel ONLY have 2 clients/sockets if the events are only to be shared between two?
Ideally what I would like to do:
Have one master channel which holds all users - then each user should be able to send a 'ping' or 'poke' to one of the other users - without all of the other clients receiving this pusher event/trigger.
I do have code but my question is really theory based and so I'm not expecting bundles of code to come from this question - but the docs on the pusher.com website kind of miss this point (or perhaps I did!)
Thanks for any input
There is an old FAQ article on how to implement 1-to-1 chat that may provide a strategy that suits your needs.

Publish data from browser app without writing my own server

I need users to be able to post data from a single page browser application (SPA) to me, but I can't put server-side code on the host.
Is there a web service that I can use for this? I looked at Amazon SQS (simple queue service) but I can't call their REST APIs from within the browser due to cross origin policy.
I favour ease of development over robustness right now, so even just receiving an email would be fine. I'm not sure that the site is even going to catch on. If it does, then I'll develop a server-side component and move hosts.
Not only there are Web Services, but nowadays there are robust systems that provide a way to server-side some logic on your applications. They are called BaaS or Backend as a Service providers, usually to provide some backbone to your front end applications.
Although they have multiple uses, I'm going to list the most common in my opinion:
For mobile applications - Instead of having to learn an API for each device you code to, you can use an standard platform to store logic and data for your application.
For prototyping - If you want to create a slick application, but you don't want to code all the backend logic for the data -less dealing with all the operations and system administration that represents-, through a BaaS provider you only need good Front End skills to code the simplest CRUD applications you can imagine. Some BaaS even allow you to bind some Reduce algorithms to calls your perform to their API.
For web applications - When PaaS (Platform as a Service) came to town to ease the job for Backend End developers in order to avoid the hassle of System Administration and Operations, it was just logic that the same was going to happen to the Backend. There are many clones that showcase the real power of this strategy.
All of this is amazing, but I have yet to mention any of them. I'm going to list the ones that I know the most and have actually used in projects. There are probably many, but as far as I know, this one have satisfied most of my news, whether it's any of the previously ones mentioned.
Parse.com
Parse's most outstanding features target mobile devices; however, nowadays Parse contains an incredible amount of API's that allows you to use it as full feature backend service for Javascript, Android and even Windows 8 applications (Windows 8 SDK was introduced a few months ago this year).
How does a Parse code looks in Javascript?
Parse works through classes and objects (ain't that beautiful?), so you first create a specific class (can be done through Javascript, REST or even the Data Browser manager) and then you add objects to specific classes.
First, add up Parse as a script tag in javascript:
<script type="text/javascript" src="http://www.parsecdn.com/js/parse-1.1.15.min.js"></script>
Then, through a given Application ID and a Javascript Key, initialize Parse.
Parse.initialize("APPLICATION_ID", "JAVASCRIPT_KEY");
From there, it's all object manipulation
var Person = Parse.Object.extend("Person"); //Person is a class *cof* uppercase *cof*
var personObject = new Person();
personObject.save({name: "John"}, {
success: function(object) {
console.log("The object with the data "+ JSON.stringify(object) + " was saved successfully.");
},
error: function(model, error) {
console.log("There was an error! The following model and error object were provided by the Server");
console.log(model);
console.log(error);
}
});
What about authentication and security?
Parse has a User based authentication system, which pretty much allows you to store a base of users that can manipulate the data. If map the data with User information, you can ensure that only a given user can manipulate specific data. Plus, in the settings of your Parse application, you can specify that no clients are allowed to create classes, to ensure innecesary calls are performed.
Did you REALLY used in a web application?
Yes, it was my tool of choice for a medium fidelity prototype.
Firebase.com
Firebase's main feature is the ability to provide Real Time to your application without all the hassle. You don't need a MeteorJS server in order to bring Push Notifications to your software. If you know Javascript, you are half way through to bring Real Time magic to your users.
How does a Firebase looks in Javascript?
Firebase works in a REST fashion, and I think they do an amazing job structuring the Glory of REST. As a good example, look at the following Resource structure in Firebase:
https://SampleChat.firebaseIO-demo.com/users/fred/name/first
You don't need to be a rocket scientist to know that you are retrieve the first name of the user "Fred", giving there's at least one -usually there should be a UUID instead of a name, but hey, it's an example, give me a break-.
In order to start using Firebase, as with Parse, add up their CDN Javascript
<script type='text/javascript' src='https://cdn.firebase.com/v0/firebase.js'></script>
Now, create a reference object that will allow you to consume the Firebase API
var myRootRef = new Firebase('https://myprojectname.firebaseIO-demo.com/');
From there, you can create a bunch of neat applications.
var USERS_LOCATION = 'https://SampleChat.firebaseIO-demo.com/users';
var userId = "Fred"; // Username
var usersRef = new Firebase(USERS_LOCATION);
usersRef.child(userId).once('value', function(snapshot) {
var exists = (snapshot.val() !== null);
if (exists) {
console.log("Username "+userId+" is part of our database");
} else {
console.log("We have no register of the username "+userId);
}
});
What about authentication and security?
You are in luck! Firebase released their Security API about two weeks ago! I have yet to explore it, but I'm sure it fills most of the gaps that allowed random people to use your reference to their own purpose.
Did you REALLY used in a web application?
Eeehm... ok, no. I used it in a Chrome Extension! It's still in process but it's going to be a Real Time chat inside a Chrome Extension. Ain't that cool? Fine. I find it cool. Anyway, you can browse more awesome examples for Firebase in their examples page.
What's the magic of these services? If you read your Dependency Injection and Mock Object Testing, at some point you can completely replace all of those services for your own through a REST Web Service provider.
Since these services were created to be used inside any application, they are CORS ready. As stated before, I have successfully used both of them from multiple domains without any issue (I'm even trying to use Firebase in a Chrome Extension, and I'm sure I will succeed soon).
Both Parse and Firebase have Data Browser managers, which means that you can see the data you are manipulating through a simple web browser. As a final disclaimer, I have no relationship with any of those services other than the face that James Taplin (Firebase Co-founder) was amazing enough to lend me some Beta access to Firebase.
You actually CAN use SQS from the browser, even without CORS, as long as you only need the browser to send messages, not receive them. Warning: this is a kludge that would make my CS professors cry.
When you perform a GET request via javascript, the browser will always perform the request, however, you'll only get access to the response if it was from the same origin (protocol, host, port). This is your ticket to ride, since messages can be posted to an SQS queue with just a GET, and who really cares about the response anyways?
Assuming you're using jquery, your queue is https://sqs.us-east-1.amazonaws.com/71717171/myqueue, and allows anyone to post a message, the following will post a message with the body "HITHERE" to the queue:
$.ajax({
url: 'https://sqs.us-east-1.amazonaws.com/71717171/myqueue' +
'?Action=SendMessage' +
'&Version=2012-11-05' +
'&MessageBody=HITHERE'
})
The'll be an error in the console saying that the request failed, but the message will show up in the queue anyways.
Have you considered JSONP? That is one way of calling cross-domain scripts from javascript without running into the same origin policy. You're going to have to set up some script somewhere to send you the data, though. Javascript just isn't up to the task.
Depending in what kind of data you want to send, and what you're going to do with it, one way of solving it would be to post the data to a Google Spreadsheet using Ajax. It's a bit tricky to accomplish though.Here is another stackoverflow question about it.
If presentation isn't that important you can just have an embedded Google Spreadsheet Form.
What about mailto:youremail#goeshere.com ? ihihi
Meantime, you can turn on some free hostings like Altervista or Heroku or somenthing else like them .. so you can connect to their server , if i remember these free services allows servers p2p, so you can create a sort of personal web services and push ajax requests as well, obviously their servers are slow for free accounts, but i think it's enought if you do not have so much users traffic, else you should turn on some better VPS or Hosting or Cloud solution.
Maybe CouchDB can provide what you're after. IrisCouch provides free CouchDB instances. Lock it down so that users can't view documents and have a sensible validation function and you've got yourself an easy RESTful place to stick your data in.

Categories

Resources