Ordering post with time and points (like reddit) firestore - javascript

I what to create a query for firebase firestore that gives me the "hottest" posts. I want a query like this to work with nodejs:
SELECT Title, LOG10(Likes + 1) * 86400 / .301029995663981 + UNIX_TIMESTAMP(Submitted) AS Hotness
FROM article
ORDER BY Hotness DESC
What is the best way of doing this with firestore?
Credit for this query: Reddit hotness score

One solution is to add a field in each post document with the value of the calculation.
Each time a post doc is updated, you would update this field through a Cloud Function (i.e. from the back-end). Since Cloud Functions code is executed with admin privileges, you can write a security rule that prevents the user directly updating this field (See the doc), and still have the field updated by the Cloud Functions.
To do the calculation, you need the nbr of likes, which you should have and the creation date.
For the creation date, just do do as follows when you create the doc:
....collection('posts').add({foo: 'bar', ..., createdOn: firebase.firestore.FieldValue.serverTimestamp()});
This way, your query is a very simple orderBy query, see the Firestore doc.

Related

How to filter out certain documents in a firestore query

I'm looking to implement a friends search function in my social app. For this I try to query for every user's document in the users collection of the DB, but it should exclude some specific documents like users who the current user is already friends with or request pending.
Is it possible to query for all the users documents, excluding specific documents by passing those documents reference ID's in Firestore.
If not, can somebody say a way to structure the data so that I can implement this functionality. Thanks.
You can use the not-in query. Here would be a simple example (taken from the docs):
citiesRef.where('country', 'not-in', ['USA', 'Japan']);
Since you want to query by the ID, you can use firebase.firestore.FieldPath.documentId() as the field name (source)
citiesRef.where(firebase.firestore.FieldPath.documentId(), 'not-in', ['123', '456']);
Alternatively you might try to use the '__name__' field-name (source):
citiesRef.where('__name__', 'not-in', ['123', '456']);
Docs for not-in: https://firebase.google.com/docs/firestore/query-data/queries#in_not-in_and_array-contains-any
Docs for documentId: https://firebase.google.com/docs/reference/js/firebase.firestore.FieldPath#static-documentid

How to use variable for "TOP" in the sqlQuery of cosmos DB bindings?

I was creating a simple page using durable function which is triggered by http request, getting data from cosmos db, and use the result as http response.
I used JavaScript and followed the Azure official documents.
In the Orchestrator, I called context.df.callActivity("Action1", {"top":10})
In the "Action1"'s function.json, I added a cosmos DB binding with sqlQuery as SELECT TOP {top} * FROM e.
I got error message:
The count value provided for a TOP clause must be an integer.
I've searched and tried using udf like SELECT TOP udf.toInteger({top}) *...
or built-in function like SELECT TOP StringToNumber({top}) *...
but none of them works.
So the question is how can I use a variable like "TOP x" in the sqlQuery for cosmos DB binding?

Stripe / node.js : how retrieve stripe subscription safely + increment 1

I just started exploring Stripe for handling payments in node.js. I want to create a payment system that goes as following:
I create a workspace and I start a Stripe subscription of 10 dollars / month.
When someone joins my workspace it will cost me 10 dollar / month extra.
So, when I want to add a person to my subscription. How would I handle this? I found the below function, but I was wondering two things:
How do I add one person to this subscription? It now says quantity: 2, but how do I simply increment 1 with every user?
in the example below I use ID 'sub_6OZnwv0DZBrrPt' to retrieve this Stripe subscription. I was wondering from where I can get this ID? I could save this subscription ID in the workspace mongo database document after I created this subscription, but I'm not sure if it is safe to keep it like that in my database? Let me know if you have any suggestions.
this is the function to update a subscription
stripe.subscriptions.update(
'sub_6OZnwv0DZBryPt',
{ quantity: 2 },
(err, subscription) => {
// asynchronously called
}
);
On 1.) you need to retrieve the current subscription based on the stored ID. This can be done as:
stripe.subscriptions.retrieve(
"sub_6OZnwv0DZBryPt",
function(err, subscription) {
// asynchronously called
}
);
The subscription object will have information about the current quantity (see the example response and doc on the subscription object). Which leads to your second question.
To retrieve the subscription you need to store the ID only. It's safe to do so, the ID is meaningless to others unless they have your test / live keys as well. Be sure you secure those keys, and feel free to store IDs like subscription_id, customer_id, etc.

Parse Query Include method not including all data expected

I am doing a query onto a class where I have a pointer to a User.
I do query.include('byUser') and when I log out the query result it's shown but when I try to get a specific attribute like email. It doesnt exist.
I also first thought it was odd that I have to get the User details by doing:
const userDetails = query.get("byUser").attributes;
Do I have to do .attributes? And also why isn't the email showing up. Everything else seems to show up in the attributes section.
Thanks
Please note that in parse, you can not query the email field of other users. you can see the email field only if you are the signed in user. This is a security mechanism.
A. If you want to get the email field for a user object, you can do two things:
Pass the user session token to the query.
new Parse.Query(Parse.User).get(<userId>,{sessionToken:<userSessionToken>});
Use master key. (Note: You have to set the master key before.)
new Parse.Query(Parse.User).find({useMasterKey:true});
B. Your include method is correct and it it will fetch the byUser object. You do not need to use .attributes.
UPDATE:
You can also set a publicEmail field in your User class which will not be filtered out by parse-server. to automate this, you can write a cloud code.
Cloud Code Example (on parse-server V 3.0.0 and above):
PLEASE NOTE THAT YOU CAN NOT USE ASYNC FUNCTIONS FOR PARSE-SERVER < V 3.0.0
Parse.Cloud.beforeSave(Parse.User, async req=>{
if (!req.original && !req.master && req.object.get('email')){
req.object.set('publicEmail',req.object.get('email'));
}
})
Now, if new user sign up, this cloud code will automatically adds a new field to the user object publicEmail which is not filtered by parse-server.

How to add new fields to existing users

I'm having a big deal - the meteor app I've been developing the last weeks is finally online. But, for an update, I need to add a field to my users profile.
I thought that walling a methods with the following code would work :
updateUsrs_ResetHelps: function(){
if(Meteor.users.update({}, {
$set: {
'profile.helps': []
}
}))
console.log("All users profile updated : helps reset");
else
throw new Meteor.Error(500, 'Error 500: updateUsrs_ResetHelps',
'the update couldn\'t be performed');
}
The problem is that my users have the classic Meteor.accounts document, whith emails, _id, services, profile, etc... but, in the profile, they don't have a .helps fields. I need to create it.
For the future users, I've modified the accounts creation function to add this fields when they sign up, but for the 200 users I already got signed up, I do really need a solution.
EDIT : Might it be because of the selector in the update ? Is a simple {} selector valid to update all the users / documents of the collection at once ?
From the Mongo documentation (http://docs.mongodb.org/manual/reference/method/db.collection.update/):
By default, the update() method updates a single document. Set the
Multi Parameter to update all documents that match the query criteria.
If you've already taken care of adding the field for new users and you just need to fix the old ones, why not just do it one time directly in the database?
Run meteor to start your application, then meteor mongo to connect to the database. Then run an update on records where the field doesn't already exist. Something like:
db.users.update({"profile.helps": {"$exists": false}}, {"$set": {"profile.helps": []}}, {multi:true})
The Mongo documentation specifies the multi parameter as:
Optional. If set to true, updates multiple documents that meet the
query criteria. If set to false, updates one document. The default
value is false.

Categories

Resources