Accepting Friend Requests functionality in Firestore? - javascript

I am trying to make the friend request functionality work, I am through with the sending and receiving requests part but I am stuck as to how to update the friends data collection for a specific user as the user accepts a friend request.
I want this to happen :
Friends (collection)
userID (document)
list of friends (their uid's)
.
.
.
.
And the list of friends gets appended with a new uid if the user accepts a new request.
Here is a screenshot of my db:

You need to first focus on how you are going to structure your data. If you want to keep 'Friends' collection to store the information about the friendship of a user, you need to first figure out what kind of queries you will be issuing on that collection.
Primarily you will need:
1. Is user A friends with User B and vice versa.
2. List of all users A is friends with.
Your current structure solves both the cases, but try to see if you can improve/optimize it for other use cases. I would leave that to you but would leave you with a hint. You are modeling a "has many" relation through a table, an efficient way would be to store a "friendship" information (user1, user2)
Answer to the original question starts here
You need to add a new key/value pair in the Friends collection for a given key.
let newRelation = {};
newRelation[friendUID] = {date: new Date().getTime()} // store whatever info you need to store here.
firestore.collection("friends").doc(uid).update(newRelation) // Udpdate the user document to add friendship
You also need to update the "friendship" for the friend, just reverse the keys for that.

Related

retrieve subscription by email stripe node.js

I want to access a subcsription, to see if the status is active.
I have this:
const subscription = await stripe.subscriptions.retrieve({
email: 'contact#Inderatech.com',
});
res.send(subscription)
however, it doesn't let me do it like this. On the stripe docs, it says to do it like this:
const subscription = await stripe.subscriptions.retrieve(
'sub_icsb2'
);
but i won't have the subscription id unless i grab it using the customer email. So is this possible?
The API only supports retrieving an object by their id. So when you want to retrieve a Subscription you need its identifier, the sub_123.
It is not possible to retrieve a Subscription by another property today and it applies to all APIs. There are List APIs that you can use to filter specific objects. For example when you list subscriptions you can filter them for a specific Price via the price parameter.
Today, the subscription doesn't have an "email" property so there isn't a way to list subscriptions for a specific email. Usually what you want is to first find the customer(s) that have a specific email address via the email parameter and then you can list subscriptions for that specific customer via the customer parameter.

How to revert reactions from GetStream.io feed

I have a question about the getStream.io NodeJS reaction API.
So I would like to build a comment system. However the comments should be loaded and displayed in the order oldest -> newest.
In the documentation I found out that I can retrieve a reaction around a certain reaction id by filtering with the parameters d_gt or d_lt.
But I think this is not the right way.
Is there an efficient way to retrieve the reactions starting with very first reaction and not with the most recent?
I appreciate every response.
Thanks!
By default, latest reactions are enriched from the feed, you can use filter API by giving an activity id to load them chronologically.
const response = await client.reactions.filter({
'activity_id': yourActivityId,
'kind': 'comment',
'id_gt': yourLastId,
'limit': 10,
});
I just ran into the same issue and just discovered that passing the activity_id as filter param retrieves reactions sorted from oldest to newest :
id_gt => activity_id
Reactions are returned in descending order (newest to oldest) by default and when using id_lt[e] , and in ascending order (oldest to newest) when using id_gt[e].
So you can pass either reaction_id to load next reactions using limit or use activity id to load first reactions.

Firestore query with only a field inside an array

This is the thing I want to accomplish: I'm building a web shop. The web shop has a React Front-end. The front-end fetches 5 collections from Firestore and displays all the items from the collection array on the shop page. A user selects an item on the shop page. I send the item fields such as (price, name, quantity, id) to my express server and the server makes a checkout session of the item fields. The user goes to a Stripe checkout form and is sent back to my front-end by Stripe when the payment is complete. I listen for that event on my server and when then want to update the quantity field of the item in Firestore.
But how do I query Firestore for this item? Is there a way to query Firestore with only this id field (or name field)? Some something like:
db
.collection('collections')
.where('id', '===', 1)
Or do I need to save the document id (of the collection) as a field inside the item map and also send that to Stripe? Or is there a better way to do this? I can't find anything online about this.
Here is a screenshot of Firestore.
Please forgive my beginner question. I'm still learning React, Firestore and Node.js.
First be sure you are sticking to the Firestore terminology correctly. There are collections and there are documents.
Collections you access via a path such as:
collRef = db.collection("products")
collRef = db.collection("products").where("quanity_on_hand", ">", "0")
collRef = db.collection("products").doc("12345").collection("purchase_history")
The latter instance can also be accessed via collRef = db.collection("products/12345/purchase_history").
In all the above cases you will get back a CollectionReference.
Documents you access such as:
docRef = db.collection("products").doc("12345")
docRef = db.doc("products/12345")
This returns you a DocumentReference for the document whose ID is "12345" in the collection "products".
So for your code example above, you want to use docRef = db.doc("collections/1") to get back the DocumentReference for the item you are after. (Or, alternatively, you could use: docRef = db.collection("collections").doc("1")
If you stick with the code that you have above, you'd get back a CollectionReference then you'd need to fetch the data with .get(), then extract the resulting documents (that will just be a single document), then work with that. Oh...and you will need to put an "id" field into all of your documents because the document's ID value (the "name" of the document) is not part of the document by default so if you want to use .where("id", "==", "1"), then you need to add an "id" field to your document and populate it correctly.
If you go with docRef = db.doc("collections/1"), you are querying for the document directly and will get back a reference to just that one. No need for extra fields, nor extracting a single document from a result set.

BigQuery similarity to "signed urls"

I have the following use case in BigQuery:
A non-trusted user will be querying a BigQuery table. Let's say the query is SELECT * FROM [bigquery.table123].
The query will return a large amount of data, let's say 200MB, which will then be displayed in the user's browser.
Our goal is to provide the most efficient way to get the 200MB data into the user's browser (and the worst way seems to do two trips instead of one -- from BQ to our server and then (compressed) to the client). I think the solution for this would probably be to enable the end (non-trusted) user to get something like a "signed-url" to perform the query directly from their browser to BigQuery. The flow would then be like this:
User issues query to our backend.
Authentication is done and a signed url is generated and passed back into javascript.
The client then sends the signed url and the data is loaded directly into the browser.
Only that exact query that has been authorized may be performed, and no other queries could be done (for example, if the client copied any tokens from the javascript)
I would never, ever want the end user to know the ProjectId or Table Name(s) that they are querying.
Is something like this possible to do in BigQuery? Here is an example of a similar need in Cloud Storage. Here is an example of an authenticated/trusted user doing this in browser: https://github.com/googleapis/nodejs-bigquery/blob/master/samples/browseRows.js or . https://stackoverflow.com/a/11509425/651174, but is there a way to do this in-browser for a non-trusted user?
Below is an option that involves two levels of authorized views. This allows to shield not only underlying data from end user - but also hides what exactly data is being used
Let's assume data is in DatasetA. Below steps explain the logic
Create InternalView in DatasetB - this one will target real data from DatasetA.
Make InternalView as Authorized View for DatasetA
Create PublicView in DatasetC - this one will target InternalView
Make PublicView as Authorized View for DatasetB
Give users read access to DatasetC
Users will be ale to run PublicView which will actually be running PrivateView against readl data.
Meantime, users will not be able to see the definition of PrivateView thus will never know ProjectId or Table Name(s) that they are querying, etc.
Note: this does not address how we'd prevent users from being able to issue queries that we haven't pre-authorized? part of your question but I am adding my answer as you asked me to do
Meantime - at least theoretically - you can embed some logic into your PrivateView, which will be querying some internal metatable with info which user and when allowed to get result. Assuming that such meta-table will be managed by your backend based on authentication/token or whatever else you have in mind
Below is simplified and brief outline of that approach
#standardSQL
WITH `projectA.datasetA.table` AS (
SELECT 'data1' col UNION ALL
SELECT 'data2' UNION ALL
SELECT 'data3'
), `projectA.datasetA.applicationPermissions` AS (
SELECT 'user1#gmail.com' user UNION ALL
SELECT 'user2#gmail.com'
), `projectA.datasetB.privateView` AS (
SELECT d.*
FROM `projectA.datasetA.table` d
CROSS JOIN `projectA.datasetA.applicationPermissions` p
WHERE LOWER(user) = LOWER(SESSION_USER())
), `projectA.datasetC.publicView` AS (
SELECT *
FROM `projectA.datasetB.privateView`
)
SELECT *
FROM `projectA.datasetC.publicView`
If user1#gmail.com or user2#gmail.com will run below query
SELECT *
FROM `projectA.datasetC.publicView`
they will get below result
Row col
1 data1
2 data2
3 data3
while if user3#gmail.com will run same very query - result will be
Row col
Query returned zero records.
Obviously, you can extend your meta-table (applicationPermissions) with for example timeframe during which user will be allowed to get result (respective lines to check time conditions will need to be added to projectA.datasetB.privateView )

Meteor: Turning email address into MD5hash on server, and accessing on client

So I want to use Gravatar avatars on my website. I got the appropriate packages for it. The way it works, it turns email addresses into an "MD5Hash." That's sent to Gravatar in exchange for the image url.
Fine, but I want to display avatars without exposing everyone's email address. At the same time, I have users already that likely already have gravatars, and I think it would be cool if their avatars just popped up one day, without adding another field to the user profiles collection, or asking them to.
Is there a way to do some of this on the server and accomplish my goal?
Handlebars.registerHelper("gravatar", function(id){
var email = Meteor.users.findOne({_id: id}).emails[0].address;
var options = {
secure: true,
size: 29,
default: 'retro'
};
var md5Hash = Gravatar.hash(email);
// 5658ffccee7f0ebfda2b226238b1eb6e
var url = Gravatar.imageUrl(md5Hash, options);
// https://secure.gravatar.com/avatar/5658ffccee7f0ebfda2b226238b1eb6e
return url;
});
Hackish:
On the server:
userArray = Meteor.users.find(query,{fields: {"emails.address": 1}}).fetch();
userArray.forEach(function(el,i,a){
a[i] = { _id: el._id, md5hash: Gravatar.hash(el.emails[0].address) };
}
where query is whatever your criteria are, will get you an array of objects whose _id matches the _id of each user and whose md5hash value is the hash of that user's email. You can set up a method to return this array to you when you need it.
The good news is that your client can use these hashes to get avatars in whatever sizes might be necessary at any time.
Much less hackish:
The problem with the above is that your server is frequently going to be recomputing the md5hash of each email. Plus you're getting a potentially big and non-reactive array from the server. You'll live to regret this. You really just want to add an md5hash key to the emails array in the user document, initialize it for existing users, and make sure that new users always have this key set at creation time. This will let you handle either single-email address users or multiple-email address users.

Categories