Giving unique names to files while uploading them - node.js

I am developing an app, in which users can post pics. So I want to ensure that every time the pic gets unique name. In PHP I use to concatenate timestamp with userId. But in node.js I am not getting the method to convert timestamp to string. So kindly suggest a way to ensure that my files don't get duplicate names.

One of the solutions would be to use UUID for a file name. But that of course depends on your applications requirements or constraints (naming convention etc.). However, if UUID as a file name would be acceptable, I recommend using node-uuid library (very easy to use!).
Sample code:
var uuidv4 = require('uuid/v4');
var filename = uuidv4() + '.png'
It is safe to use UUID as a unique identifier. You can find more on that on SO e.g. How unique is UUID?
Alternative solution (where name uniqueness is a requirement) would be to use another node.js library: flake-idgen which generates conflict-free ids based on the current timestamp. That solution guarantees unique numbers.
The solution is also very efficient, allows to generate up to 4096 ids in a millisecond per generator (you can have up to 1024 unique generators).
I hope that will help.

In node:
timestamp = new Date().getTime().toString();

If you want to use timestamp uuid's use this
var uuid = require('uuid');
// Generate a v1 (time-based) id
uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'
// Generate a v4 (random) id
uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'

//imageExt your file extension;
const imageName = Date.now() + imageExt;
Date.now() return time in milliseconds since 1st January 1970,
if the server is fast enough to process 2 images in less than 1 millisecond you will loose an image because they both will have the same name,
the better way to do this is by using uuidv4
const { v4: uuidv4 } = require("uuid");
const imageName = uuidv4() + imageExt; // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed.jpg'
uuid chance for name colision is extremely unlikely to happen.

Related

Is it safe to export Firestore data multiple times to the same storage folder? Could the overwrite break the exported data?

Here is how I'm exporting my Firestore data:
import { today } from "#utils/dates/today";
import * as admin from "firebase-admin";
admin.initializeApp({
credential: admin.credential.cert(
MY_SERVICE_ACCOUNT as admin.ServiceAccount
)});
const client = new admin.firestore.v1.FirestoreAdminClient();
const BUCKET = "gs://MY_PROJECT_ID.appspot.com/firestore-backup";
const PROJECT_ID = "MY_PROJECT_ID";
const DB_NAME = client.databasePath(PROJECT_ID, "(default)");
export const backupData = async () : Promise<void> => {
const todayDate = today(); // THIS IS YYYY-MM-DD STRING
// const hashId = generateId().slice(0,5);
const responses = await client.exportDocuments({
name: DB_NAME,
outputUriPrefix: `${BUCKET}/${todayDate}`,
collectionIds: []
});
const response = responses[0];
console.log(`Operation Name: ${response['name']}`);
return;
};
You see I'm exporting to the following path:
/firestore-backup/YYYY-MM-DD/
If I'm going to backup multiple times over the same day, can I use same date folder? Is it safe to do it? Or should I add a hash to the folder name to avoid overwriting the previous export?
PS: The overwrite on a single day is not a problem. I just don't want to break the exported data.
If you go to the bucket and check the exports you'll see that the files exported seem to follow the same pattern every time. If we were to rely only on the write/update semantics of Cloud Storage, whenever there's a write to a location where a file already exists it is overwritten. Therefore, at first it doesn't seem it would cause data corruption.
However, the assumption above relies on the internal behavior of the export operations, which may be subject to future change (let aside that I can't even guarantee them as of now). Therefore, the best practice would be appending a hash to the folder name to prevent any unexpected behavior.
As an additional sidenote, it's worth mentioning that exports could incur in huge costs depending on the size of your Firestore data.

How can I access the data set before the most recently posted ones in firebase

Currently I have a code for firebase cloud functions that is able to read the latest data set coming in using the onWrite function. However, I wish to be able to read the data set directly before the latest data set (as shown in the picture where my latest would for EG be LHYfA9GkpwOMS0OysUd and the previous data set would be LHYF9jlBmlQL5qD19-D). Is there a way to do this with firebase cloud functions? The code below shows how I get the latest data and edit it! I want to use the latest data's etotal value to subtract that from the previous data's etotal value.
edit: my data values wont be replacing the previous set so I cannot use 'previous'
exports.editData = functions.database.ref('/AllData/immaphoton/A/{id}').onWrite((change, context) => {
const afterData = change.after;
if (afterData.exists()) {
//console.log('hey');
const data = afterData.val();
// set of data to multiply by turns ratio
var actualEIn = (data.ein)*200;
var actualEOut = (data.eout)*200;
var totalE = (actualEIn - actualEOut);
var actualTotalPower = (data.tp)*200;
var ISOts = (data.ts);
// add timezone offset to milliseconds
var localTS = moment(Date.parse(data.ts) + (8*1000*60*60)).format('YYYY-MM-DD');
// need to change ts to suit each type of data
}
return admin.database().ref('/editedData/immaphoton/A').push({
ein: actualEIn,
eout: actualEOut,
etotal: totalE,
tp: actualTotalPower,
timestamp: ISOts,
localtime: localTS,
});
});
If you know the key of the new child node, you can read the item before it by combining orderByKey().limitToLast():
var key = context.params.id; // key of new/updated child
var ref = admin.database().ref('/editedData/immaphoton/A');
var query = ref.orderByKey().endAt(key).limitToLast(2);
query.once("child_added").then(function(snapshot) {
console.log(snapshot.key);
});
This code is not dependent on running in Cloud Functions, except for how it determines the value of key. If you can determine the key another way, this would run with any of the Firebase JavaScript SDKs.

How to query firebase realtime database in cloud code

I am using Firebase cloud code and firebase realtime database.
My database structure is:
-users
-userid32
-userid4734
-flag=true
-userid722
-flag=false
-userid324
I want to query only the users who's field 'flag' is 'true' .
What I am doing currently is going over all the users and checking one by one. But this is not efficient, because we have a lot of users in the database and it takes more than 10 seconds for the function to run:
const functions = require('firebase-functions');
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
exports.test1 = functions.https.onRequest((request, response) => {
// Read Users from database
//
admin.database().ref('/users').once('value').then((snapshot) => {
var values = snapshot.val(),
current,
numOfRelevantUsers,
res = {}; // Result string
numOfRelevantUsers = 0;
// Traverse through all users to check whether the user is eligible to get discount.
for (val in values)
{
current = values[val]; // Assign current user to avoid values[val] calls.
// Do something with the user
}
...
});
Is there a more efficient way to make this query and get only the relevant records? (and not getting all of them and checking one by one?)
You'd use a Firebase Database query for that:
admin.database().ref('/users')
.orderByChild('flag').equalTo(true)
.once('value').then((snapshot) => {
const numOfRelevantUsers = snapshot.numChildren();
When you need to loop over child nodes, don't treat the resulting snapshot as an ordinary JSON object please. While that may work here, it will give unexpected results when you order on a value with an actual range. Instead use the built-in Snapshot.forEach() method:
snapshot.forEach(function(userSnapshot) {
console.log(userSnapshot.key, userSnapshot.val());
}
Note that all of this is fairly standard Firebase Database usage, so I recommend spending some extra time in the documentation for both the Web SDK and the Admin SDK for that.

generate random unique token for user id

I want to generate token as user id and store in database , but how to generate unique one?
should I add timestamp var currentUnixTimestamp = (new Date().getTime() / 1000); as salt? how to do with crypto?
var generateToken = function() {
return new Promise(function (fulfill, reject){
crypto.randomBytes(8, function(error, buf) {
if (error) {
reject(error);
} else {
var token = buf.toString('hex');
fulfill(token);
}
});
});
};
Eight random bytes from a properly seeded crypto library has a low chance of a collision, so you don't usually need to concern yourself with duplicates. In fact, increase that to 16 bytes, and your code is on par with UUID version 4. This is considered a standard for UUIDs. The chances of a collision are so remote it is not usually worth considering.
If you are going that far though, consider using a standard format UUID, such as the node package "uuid". There are also database-side uuid functions which you can add as default to schemas e.g. in Postgres. The advantage is a standardised and well-understood format for your ids, and you won't need to spend any time justifying or maintaining your code for this, just point developers to the standard docs.
If you want this token for authentication purposes you should use json web token instead. It will manage for you and its quite efficient.
Only have to include as a middleware .
app.use(expressJWT({
secret: new Buffer("Your-secret-key").toString('base64')
}).unless({
//# pass api without validating
path: unlessRoutes
}));
You could specify which routes you don't want to to skip in jwt middleware by giving an array in unlessRoutes.
var unlessRoutes = [
'/',
/\/login/,
/\/register/,
/\/customers/,
/\/customer$/,
/\/addCustomer/,
/\/just/,
/\/search/,
/\/dynamic/,
/\/favicon.ico/
]
This is what i think we can do for generating the random token using the crypto:
var passwordResetToken = createRandomToken(data.body.email);
exports.createRandomToken = function (string) {
var seed = crypto.randomBytes(20);
return crypto.createHash('abcde').update(seed + string).digest('hex');
};

How to store UUID as an alphanumeric in nodejs

Node-uuid provides an excellent package to generate uuid
https://github.com/broofa/node-uuid
// Generate a v4 (random) id
uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'
However, it does not provide a way to encode it in base64 or alphanumeric string.
Is there an easy way to do this?
Install;
https://github.com/RGBboy/urlsafe-base64
Then;
var uuid = require('node-uuid');
var base64 = require('urlsafe-base64');
base64.encode(Buffer(uuid.v4()));

Resources