Voting Network Architecture - angularjs

Alright, My question could be a bit long, so kindly bear with me.
I don't have any bug or some error but it's more about conceptual question.
I am building a social network website, much like 9gag.com , So I have this up-votes and down-votes feature which will be associated with Posts, Comments and Replies made by the user.
I am building this website on Laravel and Angular and as my back-end and front-end frameworks respectively. And I have managed to built it as well.
Now everything is working great except I am sending 2 requests (HTTP) per comment and reply to ensure whether a user has already upvoted or downvoted that certain comment or reply. and in backend I do my querying to find whether he did or not and apply ng-classes accordingly but that just takes too much time and well obviously if there are 10 comments (limit) then it will make 20 requests, so my question is how to handle these whether logged In user has did this or not scenarios in the most elegant way?

Include the vote status in the API response that lists the comments.
Your API response should looks something like this for a logged-in user:
[{
"id": 123,
"text": "This is the comment. I voted it up.",
"vote": "up"
},
{
"id": 456,
"text": "This is another comment. I haven't voted on it.",
"vote": null
}
{
"id": 789,
"text": "This is another comment. I didn't like this one so I voted it down.",
"vote": "down"
}]

Related

Storing data from MongoDB to state - best option

I'm a newcomer to the MERN stack and just putting a little blog site project together for some practice...
In my case, I'm retrieving all the blog posts to list briefly on the home screen each with a link to the full blog article. In this case the data is already retrieved and stored in React state.
Question is, when I go to the full blog article is it better to take the data from the already retrieved full list of blogs saved in state or should I get the individual blog entry from the database again with using ID.
I'm confident implementing either - I'm just considering the best practice, or benefits/dangers of doing either? Could data get out of sync?
I'm a newbie - be gentle!
Thanks for all advice.
I think when fetching all blogs for home page, you should only fetch the data which you will show for each blog rather than fetching the whole blog.
Lets assume each of your blog has following fields:
{
"title" : "Title of blog",
"body" : "This is my blog, ...."
"comments": [comment1, comment2, ...]
"upvotes" : [],
"downvotes" : [],
"author" : ObjectId("ref to the author schema"),
"time" : 10:30 PM
}
on home page, i'm assuming you only need to show the author, title, time and some lines of the body so you need to only fetch those instead of getting the whole blog.
For that you can use .select() function of mongoose:
const blogs = await Blogs.find({}).select({ title: 1, time: 1, body: 1, author: 1 });
This way, you will only be getting the data you require. By implementing this, when a user clicks on a blog to view it, you can re-fetch the whole blog and get the latest result (in case the blog was updated or new comments/votes were added, the changes will be reflected).
Hope this answers your question.

How to create the following data structure in a NoSQL environment

Intro
I have a FireStore database similar to a social media db, with 3 collections Users, Events, and EventUpdates. My goal is to create a feed with eventUpdates created by me and my friends. So i have to expand my database with friendship connections. But i struggle with 3 problems, and hopefully somebody here can push me in the right direction to solve these.
Problem/Question 1:
I added username and user image to the EventUpdate model so it's easier to query. I've heard denormalise is the way to go in a NoSQL database. But if a user updates his user image, i've to update all eventUpdates created by that user. Sounds like something you don't wanne do. But is there a better way to do this?
Problem/Question 2:
How can i create a data structure that is optimised for performing the following query: get eventUpdates from me and my friends ordered by date.
Problem/Question 3:
How to store likes? I can keep a counter in a eventUpdate. But this becomes a problem when i denormalise eventUpdates (see current solution underneath EDIT)..
Data structure example .
{
"users": {
"1": { "name": "Jack", "imageUrl": "http://lorempixel.nl" }
},
"events": {
"A": {
"name": "BeerFestival",
"date": "2018/09/05",
"creatorId": "1"
}
},
"eventUpdates": {
"1": {
"timestamp": "13243543",
"creatorId: "1",
"creatorName": "Jack",
"creatorImageUrl": "http://lorempixel.nl",
"eventId": "A",
"message": "Lorem ipsum"
}
}
}
EDIT
OK, after some trial and error i ended up with the following structure. This structure seems work, but my problem with this solution is that i need to make a lot of write calls to update a single eventUpdate because of all the copies in each feed (1000 followers means 1000 copies). And it looks like i need to do that a lot.
I would like for example to add a like button to each event update. This trigger an update on all EventUpdate copies. For me it looks like firebase is not suited for my project and i'm thinking of replacing it with a SQL DB, or can anyone here change my mind with a better solution?
{
"users": {
"user1": { "name": "Jack",
"imageUrl": "http://lorempixel.nl",
"followers": ["user1"]
}
},
"feeds": {
"user1": {
"eventUpdates": {
"1": {
"timestamp": "13243543",
"creatorId: "1",
"eventId": "A",
"message": "Lorem ipsum"
}
},
"following": {
"user1": {
"name": "Jack",
"imageUrl": "http://lorempixel.nl",
"followers": ["user1"]
}
}
},
"events": {
"A": {
"name": "BeerFestival",
"date": "2018/09/05",
"creatorId": "1"
}
}
}
I added username and user image to the EventUpdate model so it's easier to query. I've heard denormalise is the way to go in a NoSQL database.
That's right, denormalization and is a common practice when it comes to Firebase. If you are new to NoQSL databases, I recommend you see this video, Denormalization is normal with the Firebase Database for a better understanding. It is for Firebase realtime database but same rules apply to Cloud Firestore.
But if a user updates his user image, i've to update all eventUpdates created by that user. Sounds like something you don't wanne do. But is there a better way to do this?
Yes, that's also correct. You need to update all the places where that image exists. Because you have chosen google-cloud-firestore as a tag, I recommend you see my answer from this post because in case of many write operations, Firestore might be a little costly. Please also see Firestore pricing plans.
Regarding Firestore, instead of holding an entire object you can only hold a reference to a picture. In this case, there is nothing that you need to update. It's always a trade between these two techniques and unfortunately there is no way between. You either hold objects or only references to objects. For that, please see my answer from this post.
How can i create a data structure that is optimised for performing the following query: get eventUpdates from me and my friends ordered by date.
As I see, your schema is more a Firebase realtime database schema more than a Cloud Firestore. And to answer to your question, yes you can create. So talking about Firestore, you can create a collection named eventUpdates that can hold eventUpdate objects and to query it according to a timestamp, a query like this is needed:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference eventUpdatesRef = rootRef.collection("eventUpdates");
Query query = eventUpdatesRef.orderBy("timestamp", Query.Direction.ASCENDING);
But please note that the timestamp field should be of type Date and not long. Please also take a look at my answer from this post, to see how you can add a date property in a Cloud Firestore database.
How to store likes? I can keep a counter in a eventUpdate. But this becomes a problem when i denormalise eventUpdates (see current solution underneath EDIT)
You can simply add likes but I recommend you see the last part of my answer from this post. So you might consider adding that count in a Firebase realtime database rather than in Cloud Firestore. Both databases work very well together.
This structure seems work, but my problem with this solution is that i need to make a lot of write calls to update a single eventUpdate because of all the copies in each feed (1000 followers means 1000 copies). And it looks like i need to do that a lot.
You might also take a look at my answer from this post.
For me it looks like firebase is not suited for my project and i'm thinking of replacing it with a SQL DB, or can anyone here change my mind with a better solution?
I don't think this way. There are many apps out there that have the exact mechanism as yours and are working very well.
If you want your feed items to be in sync with the real users data (new profile image when the user changes it for example) you can simply store the user ID in the eventUpdate document. This way you don't have to keep them in sync manually, and every time you have to display the item in the feed you could simply fetch user data, and easily query many eventUpdates on userId and created_at fields ( assuming you have them ).
To implement likes in your feed the solution depends on a bunch of things like traffic volume.
The simplest way is to update a likes field with a transaction, but Firestore has a maximum updates frequency on a single document of 1 second. Plus, a transaction can easily fail if more than 5 transactions are trying to update the same document.
To implement a more solid likes system take a look at this page from the official Firebase docs.
Firestore has a different approach to the NoSQL world. Once you know the data you will use (as You already do) there are some very important points about what architecture the data will have. And It depends a lot about how the data grows, what kind of queries you will need and how often you will use them. Some cases You can create a root collection that aggregates data and queries might be easier.
There is a great video from Firebase Channel that might help. Check it out!
How to Structure Your Data | Get to Know Cloud Firestore #5
https://www.youtube.com/watch?v=haMOUb3KVSo
[UPDATED] December 26th
Others videos that might help to model and query your data is these videos:
How to Connect Firebase Users to their Data - 3 Methods
https://www.youtube.com/watch?v=jm66TSlVtcc
How to NOT get a 30K Firebase Bill
https://www.youtube.com/watch?v=Lb-Pnytoi-8
Model Relational Data in Firestore NoSQL
https://www.youtube.com/watch?v=jm66TSlVtcc

Alexa Skill - How to get complete text of statement asked to alexa

I am creating an Alexa skill, I have coded several custom and default intents and they are working fine.
Now I want to write a fallback intent wherein I want to get the exact statement asked/sent to Alexa skill, is there a way wherein we may get the entire question string/text that has been asked to Alexa skill. I know we can get slot values and intent information, but I need the entire text statement sent to skill.
Thanks
Well, I had faced the same issue. After trying several methods, I have got the complete text of the statement asked Alexa.
You have to make the following setup in your Alexa skill (name of intent, slot name, and slot type you can choose as per your need)
Setting up Intent
Setting up custom slot type
After setting up your Alexa skill you can invoke your skill, keep some response for launch request and say anything you want, you can catch the entire text as shown here.
"intent": {
"name": "sample",
"confirmationStatus": "NONE",
"slots": {
"sentence": {
"name": "sentence",
"value": "hello, how are you?",
"resolutions": {
"resolutionsPerAuthority": [
{
"authority": "xxxxxxx",
"status": {
"code": "xxxxxxx"
}
}
]
},
"confirmationStatus": "NONE",
"source": "USER"
}
}
}
Note*: In this method you will need to handle utterances properly if there are more than one intent.
There's no way to get the whole utterance straight from a top level intent. Right now the closest you can get is using a custom slot with type AMAZON.SearchQuery (not a custom type as suggested in another answer) but you will have to define an anchor phrase in your utterance that goes before the slot. For example, you would define an utterance like:
search {query}
where query is a slot of type AMAZON.SearchQuery.
The anchor search in the utterance is mandatory (a requirement of the SearchQuery type), so as long as the user starts the utterance by saying search, anything that follows will be captured which is pretty close to what you want to achieve.
Having said that there's actually one indirect way to approximate capturing the whole utterance the user is saying (filtered by NLU) leveraging AMAZON.SearchQuery but only as part of an ongoing dialog using Dialog Management. If you're engaging in a dialog of this kind where Alexa automatically uses defined prompts to solicit slot information you can define an utterance that is a single isolated slot of type AMAZON.SearchQuery with no anchor. Example:
Alexa: Ok, I will create a reminder for you. Please tell me the text of the reminder
User: Pick of the kids from school
Alexa: Ok. I will remind you to Pick up the kids from school
In the example above Alexa detects that the user wants to send a reminder but there's no reminder text set up so it elicits the slot. When you, as a developer, define the prompts that Alexa needs to ask you also define the possible reponses. In this case you can define a response utterance as just:
{query}
and capture the whole thing the user says in response to the prompt, like e.g. "pick up the kids from school"
The English US language has a Slot Type called AMAZON.LITERAL that lets you capture the exact phrase or sentence used (depending on how it's used in your utterance). This Slot Type, however, isn't available in other regions.
Amazon also don't recommend using it:
Although you can submit new and updated English (US) skills with
AMAZON.LITERAL, custom slot types provide better accuracy than
AMAZON.LITERAL in most cases. Therefore, we recommend that you
consider migrating to custom slot types if possible. Note that
AMAZON.LITERAL is not supported for any language other than English
(US).
See: https://developer.amazon.com/docs/custom-skills/literal-slot-type-reference.html
There once used to be a slot type called Amazon.LITERAL, that was allowed to be used in specific regions. However, it has now been either deprecated (or removed).
There is however another solution to this problem using custom slots.
Let's say we are creating a Food Ordering System on Alexa. A skill for something like Zomato or Yelp for Alexa. Let us give the skill the invocation name robert.
So first we make a list of the type of statements which are going to be made. You can skip this step if your skill isn't this specific. However, this just helps you define the type of statements your skill might expect to encounter.
Alexa order robert to send me a chicken steak with mashed potatoes.
Alexa ask robert to recommend me some good Indian restaurants near me.
Alexa please tell robert to rate Restaurant XYZ's recent delivery with a single star.
After we have made a list of statements we store them in a csv file.
We go ahead and click on the Add button beside Slot Types.
Give your Custom Slot Type a name.
Now once you are done with this, come up with the list of constructs in which your skill can be invoked. Some of them have been given below.
Alexa ask robert to ...
Alexa make robert ...
Alexa order robert to ...
Alexa tell robert to ...
The three dots (...) represent the actual part of the order/statement. This is the text which you are interested in extracting. An example would be; for the statement,
Alexa ask Robert to send me a bucket of chicken nuggets.
you would be interested in extracting only the portion in bold.
Now Amazon classifies statements based on intent. They have five default, predefined intents for Welcome, Cancelling, Help and other basic functionalities. We go ahead and create a custom intent for dealing with the mainstream statements that will be used to primarily interact with our skill.
Under the new Custom Intent Window, at the bottom of the page is the space to add slots which will be used in your intent. We add our previously created custom slot and name it literal. (You can name it anything)
The custom slot, literal in our case, is the text we want to be extracted out of the user's statements.
Now we go ahead and replace the three dots (...) in the list of constructs with {literal} and add it to the list of sample utterances.
For the statement
Alexa order robert to send me a chicken steak with mashed potatoes.
The JSON would contain a section like this for the custom intent and highlighting the custom slot text.
"request": {
"type": "IntentRequest",
"requestId": "",
"timestamp": "2019-01-01T19:37:17Z",
"locale": "en-IN",
"intent": {
"name": "InteractionIntent",
"confirmationStatus": "NONE",
"slots": {
"literal": {
"name": "literal",
"value": "to send me a chicken steak with mashed potatoes.",
"resolutions": {
"resolutionsPerAuthority": [
{
"authority": "",
"status": {
"code": ""
}
}
]
},
"confirmationStatus": "NONE",
"source": "USER"
}
}
}
}
Under the slots subsection under the custom intent we have our literal slot whose value gives us the text of the user's speech.
"slots": {
"literal": {
"name": "literal",
"value": "to send me a chicken steak with mashed potatoes."

Coinbase payment iframe switching api versions

I am setting up my site to use the Coinbase iframe for accepting payments.
I am testing using the sandbox.
Sometimes when I make a payment the callback to my server takes the form:
{
"order": {
"id": "YDWALXJW",
"uuid": "2a6de442-be7b-5517-9b49-f00908460115",
"resource_path": "/v2/orders/2a6de442-be7b-5517-9b49-f00908460115",
"metadata": null,
"created_at": "2015-12-06T16:58:02-08:00",
"status": "completed",
...
and other times it looks like this:
{
"id": "f08d1f11-27f9-5be2-87fd-e086d1b67cab",
"type": "wallet:orders:paid",
"data": {
"resource": {
"id": "309a20df-a8e6-532d-9a2b-3ce5ea754d6d",
"code": "52N6TG58",
"type": "order",
...
I realize this is probably just api v1 vs v2, but I don't understand why it seems to be randomly switching back and forth. Any ideas of how to make it just use v2?
Thanks.
Most likely you've entered the same URL as both a Notifications (v2) and Callback (v1) URL.
This is easy to do, given that there are 3 different places in the UI where you can provide either or both the callback/notifications URL.
Merchant Settings Page
Your API Key's Edit form
The Merchant Tools Generator
You'll receive a POST message for each place you've entered this URL. (I was able to get 5 unique POSTs in my testing!)
The right place to include the URL depends on your situation:
If you just want merchant notifications (paid orders, mispaid orders and payouts), put it in the Merchant settings page.
If you are building an app with functionality beyond merchant tools, and want a broader set of wallet notifications, put it in your API Key's Edit form.
For Merchants I would generally not recommend entering the URL for a button generated via option 3. Based on the title of your question, I'm guessing this is your situation.
You won't be able to view or edit this setting in the future. If you're re-using a static button that you've previously generated, and think that you've included a URL there which you'd like removed, you'll need to replace the button by generating a new one.
I hope that helps!

Multiple Menu Items on a card, including pinning

EDIT: After the excellent answer below by Prisoner I'm leaving the question for my humility and for search posterity, but please note I made a mistake in the formation of my question. I misunderstood one piece of background documentation - multiple menu Items per card ARE supported.
I am trying to place a fixed card in the pinned group (left of the home card) and let the user select it and submit a reply. The application thinking is that this lets the user submit commands to the web app which the web app then processes and sends response cards to the user.
I've done the research to know I can't set isPinned to true directly from my app, instead that has to be done by the user via a menuItem. I have that working. For example this works to let a user pin my card:
{
"text": "Test pinnable card",
"menuItems": [
{
"action": "TOGGLE_PINNED",
"values": [{
"displayName": "Pin Card",
"iconUrl": "https://<Graphics URL>"
}]
}
]
}
That is working and arrives at my Glass just fine and I can pin and unpin it no problem.
But once I've set that menuItem to allow a user to pin the card, is there a way to let the user reply? According to this entry there can only be one menuItem per card. That would seem to imply any pinned card can't have menu items and therefore no reply functions (at least I don't know another way to do replies).
I would very much like to let the user select the card and send voice replies. I can do that in a NON-PINNED card using this menuItem:
"menuItems": [
{
"action": "REPLY",
"values": [
{
"displayName": "Search",
"iconUrl": "https:<Graphics URL>"
}
]
}
So the question is basically whether anybody knows a way to either load both menuItems onto a card or to somehow add or exchange to apply the second menuItem once a card is pinned. My guess would be I can't replace the menuItem after pinning or it could be abused to make cards a user couldn't unpin, but it also seems kind of useless to make any pinned card not have actions.
My apologies if there are "obvious" workarounds, I'm plumb out of ideas.
I have glass, running Glassware on AppEngine, and can test any theories people have. This seems like a pretty basic need for Glassware that would be used alot. I'm working on an enterprise document sorting and data finding application, for those who are curious.
A few things.
First, the answer you referenced doesn't say that there can be only one menuItem per card. What it says is there can only be one menu per set of htmlPages, meaning that each card had to have the same menu. HtmlPages are now deprecated in favor of HTML that is split, partly because of the confusion of that question.
Second, you can absolutely have more than one item in the menuItems setting. Hence the plural and use of the array. :)
Third, it looks like you are trying to set "values" for card actions that do not take values (TOGGLE_PINNED and REPLY). Values are only needed for CUSTOM actions.
Fourth, make sure that you have a "creator" set for the REPLY type.
See https://developers.google.com/glass/v1/reference/timeline/insert for details, but in general, what you will need to do is to set the menuItems field to an array, with each element in the array having a different action. You will also need a creator field set to reply to. So something like this should work (although I haven't tested this specific one):
{
"text": "Test pinnable card",
"creator": {
"id": "harold"
"displayName": "Harold Penguin",
"imageUrls": ["https://developers.google.com/glass/images/harold.jpg"]
},
"menuItems": [
{
"action": "TOGGLE_PINNED"
},{
"action": "REPLY"
},{
"action": "CUSTOM",
"values": [
{
"displayName": "Search",
"iconUrl": "https:"
}
]
}
]
}
Finally, you may wish to reconsider using a pinned card to do this. This method harkens back to a very app-centric way of doing things, which is somewhat counter to how Glass tends to work. If you would like to add voice commands, consider registering contacts that can accept commands. See https://developers.google.com/glass/v1/reference/contacts for more details.

Resources