Get Document Id's that satisfy the condition in a Query - node.js

I want to get document id which satisfies a given query in cloud firestore.
The schema for my database is like this
deyaPayusers/AuthId
/user details
PhoneNo:
/Wallet
/Transaction
I know PhoneNo, then is there a way to get the corresponding AuthId.
I implemented my idea as described below and I'm encountering this error
Argument "documentPath" is not a valid ResourcePath. Path must be a
non-empty string.
const functions = require('firebase-functions');
const Firestore = require('#google-cloud/firestore');
const firestore = new Firestore();
const admin = require('firebase-admin');
exports.transactionDetails = functions.firestore
.document('deyaPayusers/{authid}/Transaction/{authid1}')
.onWrite(event=>{
const db1 = admin.firestore();
const MAuth = event.params.authid
const transid = event.params.authid1
var payeeDocId
var newValue = event.data.data();
var payee = newValue.Payee;//Phone number of money receiver
var amt = newValue.Amount;//Amount willing to pay to payee(money receiver)
var usersRef = db1.collection('deyaPayusers').doc(MAuth);//Refers to payer doc
var payer = usersRef.PhoneNo;//Gets Phonenumber attribute of payer
const walletRefPayer = db1.collection('deyaPayusers').doc(MAuth).collection('Wallet').doc(MAuth);//Wallet reference of Payer
var walletAmt = walletRefPayer.Usd//Accessing the total amount of a person(payer) stored in the wallet
//Getting the payee details assuming, payee has an account in DeyaPay else we need to send the invite to the payee
var payeeInfo = db1.collection('deyaPayusers');//Query to retrieve the payee details from his phone number
let payeeQuery = payeeInfo.where('PhoneNo','==',payee)//We are retrieving it here,before checking the condition because we need to update the transaction details with status either it is failure or success
.get()//To get the doc ID of the Payee based upon the PhoneNo
.then(snapshot => {
snapshot.forEach(doc=>{
payeeDocId = doc.id;
}
});
/*.catch(err =>{
console.log('Error getting documents',err);
});*/
//const docID = payeeQuery.getId();//Gets the Document ID of the payee with the above phone number,in our case it is Authenticated ID.
var payeeWalletRef = db1.collection('deyaPayusers').doc(payeeDocId).collection('Wallet').doc(payeeDocId);
if(walletAmt>=amt){
//Write transactions here,becuase both actions(increment and decrement) must complete together
var payeeTransaction = db1.runTransactions(pT=>{
return pT.get(payeeWalletRef)
.then(doc =>{
var payeeDoc = doc.data(Usd)+amt;//Crediting the amount to be added
return pT.update(payeeWalletRef,{
Usd:payeeDoc});//end of update
})
})//end of payeeTransaction
var payerTransaction = db1.runTransactions(ev=>{
return ev.get(walletRefPayer)
.then(doc=>{
var payerDoc = doc.data(Usd)-amt;//Debitting the amount to be transfered
return ev.update(walletRefPayer,{
Usd:payerDoc});//end of update
});//end of then for payerTransaction
})//end of payerTransaction
}
});//onWrite() end

.document('deyaPayusers/{authid}/Transaction/{authid1}')
You aren't properly interpolating this string.
You need
.document(`deyaPayusers/{authid}/Transaction/{authid1}`)
Also, if you're coming here from google. Any non-string parameter to .document will result in this exception as well.

Related

Tron - Sign a transaction in JS (NodeJS)

I am trying to sign a build & sign transaction then create a hex to broadcast the transaction on TRON Network.
I have successfully done this but when i broadcast this transaction i am getting "TRON TAPOS_ERROR" error.
I have searched and got the reason that i have to include last block number and hash.
check this : https://github.com/tronprotocol/java-tron/issues/857
But I don't know how to do this.
I have tried this code :
const CryptoUtils = require("#tronscan/client/src/utils/crypto");
const TransactionUtils = require("#tronscan/client/src/utils/transactionBuilder");
async function transferContractTx() {
const fromAddress = "FROM_ADDRESS";
const toAddress = "TO_ADDRESS";
const privateKey = "MY_PRIVATE_KEY";
const token = "TRX";
const amount = 1000000;
let transaction = TransactionUtils.buildTransferTransaction(token, fromAddress, toAddress, amount);
console.log(JSON.stringify(transaction));
let signedTransaction = CryptoUtils.signTransaction(privateKey, transaction);
console.log(signedTransaction);
}
transferContractTx();

Firebase functions multi child change

hi firebase functions I want to change multiple children, but cannot change all children under user id. can you help me with this topic
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
var database = admin.database();
exports.newNodeDetected = functions.database.ref('system/{userId}/value')
.onWrite((Change) =>{
var oldDeger = Change.before.val();
var newDeger = Change.after.val();
if (newDeger === '0'){
database.ref(`system/${userId}/value`).set('1');
}
})
enter image description here
You can update multiple children in several ways using standard object manipulation and direct writes as demonstrated in your question.
You may be interested in using update rather than set when updating multiple fields.
You will also notice I added a Context field which allows you to access information such as the userID from the reference path and other information: Source
exports.newNodeDetected = functions.database.ref('system/{userId}/value')
.onWrite((Change, Context) =>{
var oldDeger = Change.before.val();
var newDeger = Change.after.val();
if (newDeger === '0'){
database.ref(`system/${Context.params.userId}/value`).set('1');
database.ref(`system/${Context.params.userId}/otherField`).update({another:field});
}
})
Resource: Medium Article: Realtime Set Vs Update

Using wildcards in firestore get query

I want to create a cloud function in firebase that gets triggered whenever a user logs in for the first time. The function needs to add the UID from the authentication of the specific user to a specific, already existing document in firestore. The problem is that the UID needs to be added to a document of which I do not know the location. The code I have right now doesn't completely do that, but this is the part where it goes wrong. The database looks like this when simplified
organisations
[randomly generated id]
people
[randomly generated id] (in here, a specific document needs to be found based on known email
adress)
There are multiple different organisations and it is unknown to which organisation the user belongs. I thought of using a wildcard, something like the following:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
console.log('function ready');
//Detect first login from user
//if(firebase.auth.UserCredential.isNewUser()){
if(true){
//User is logged in for the first time
//const userID = firebase.auth().currentUser.UID;
//const userEmail = firebase.auth().currentUser.email;
const userID = '1234567890';
const userEmail = 'example#example.com';
//Get email, either personal or work
console.log('Taking a snapshot...');
const snapshot = db.collection('organisations/{orgID}/people').get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log(doc.data());
});
});
}
I commented out some authentication-based lines for testing purposes. I know the code still runs, because hardcoding the orgID does return the right values. Also, looping trough every organisation is not an option, because I need to have the possibility of having a lot of organisations.
A lot of solutions are based on firestore triggers, like onWrite, where you can use wildcards like this.
However, I don't think that's possible in this case
The solution to the problem above:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
//Add UID to document in DB[FMIS-94]
//Detect first login from user
//if(firebase.auth.UserCredential.isNewUser()){
if(true){
//User is logged in for the first time
//const userID = firebase.auth().currentUser.UID;
//const userEmail = firebase.auth().currentUser.email;
const userID = '1234567890';
const userEmail = 'example#example.com';
var docFound = false;
//Get email, either personal or work
console.log('Taking a snapshot...');
//Test for work email
const snapshot = db.collectionGroup('people').where('email.work', '==', userEmail).get()
.then(function(querySnapshot){
querySnapshot.forEach(function(doc){
//work email found
console.log('work email found');
console.log(doc.data());
docFound = true;
const organisationID = doc.ref.parent.parent.id;
writeUID(doc.id, userID, organisationID);
});
});
if(!docFound){
//Test for personal email
const snapshot = db.collectionGroup('people').where('email.personal', '==', userEmail).get()
.then(function(querySnapshot){
querySnapshot.forEach(function(doc){
//personal email found
console.log('personal email found');
console.log(doc.data());
const organisationID = doc.ref.parent.parent.id;
writeUID(doc.id, userID, organisationID);
});
});
}
}
async function writeUID(doc, uid, organisationID){
const res = db.collection(`organisations/${organisationID}/people`).doc(doc).set({
userId: uid
}, { merge: true });
}
This was exactly what I needed, thanks for all your help everyone!
It is not possible to trigger a Cloud Function when a user logs in to your frontend application. There is no such trigger among the Firebase Authentication triggers.
If you want to update a document based on some characteristics of the user (uid or email), you can do that from the app, after the user has logged in.
You mention, in your question, "in here, a specific document needs to be found based on known email address". You should first build a query to find this document and then update it, all of that from the app.
Another classical approach is to create, for each user, a specific document which uses the user uid as document ID, for example in a users collection. It is then very easy to identify/find this document, since, as soon the user is logged in you know his uid.
I'm not sure I understand you correctly, but if you want to search across all people collections not matter what organizations document they're under, the solution is to use a collection group query for that.
db.collectionGroup('people').get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log("user: "+doc.id+" in organization: "+doc.ref.parent.parent.id);
});
});
This will return a snapshot across all people collections in your entire Firestore database.
First setup Cloud Functions according to the official Documentation.
Then after setting up create functions like this:
exports.YOURFUNCTIONNAME= functions.firestore
.document('organisations/[randomly generated id]/people/[randomly generated id]')
.oncreate(res => {
const data = res.data();
const email = data.email;/----Your field name goes here-----/
/-----------------Then apply your logic here---------/
)}
This will triggers the function whenever you create the People -> Random ID

Ethereum sending with web3.js is not working today (the result is fail)

This is my web3.js function to send the ETH.
It works perfectly last month. But today It is not working well.
It took more than 1~5 min and then return the fail.
Some times it sent but It also takes very long time to complete the transaction.
Please help me with this problem.
This is my current codes.
var web3 = new Web3(new Web3.providers.HttpProvider('https://mainnet.infura.io/GfgWbe8c2O82N18RRSuJ'));
// Who holds the token now?
var myAddress = address;
// This file is just JSON stolen from the contract page on etherscan.io under "Contract ABI"
return await web3.eth.getBalance(myAddress);
}
const sendETHCoin = async (from_addr, to_addr, amount, private_key, fee) => {
var content = fs.readFileSync(base_path + 'abiDefinitions/ethAbiContract.json');
content = JSON.parse(content);
///////////////////////////////////
// connect to Infura node
var web3 = new Web3(new Web3.providers.HttpProvider('https://mainnet.infura.io/GfgWbe8c2O82N18RRSuJ'));
// the address that will send the test transaction
const addressFrom = from_addr;
const privKey = private_key;
// the destination address
const addressTo = to_addr;
var gasPrice = "0x02540BE400";
var gasLimit = "0x250CA";
if(fee == ''){
fee = parseInt(gasPrice, 16) * parseInt(gasLimit, 16);
}else{
gasPrice = parseInt(parseInt(fee)/parseInt(gasLimit, 16))+1;
if(gasPrice < 1){
gasPrice = 1;
}
gasPrice = "0x"+gasPrice.toString(16);
}
//gasPrice = "0x03540BE400";
var txCount = await web3.eth.getTransactionCount(addressFrom);
const txData = {
nonce: web3.utils.toHex(txCount),
gasLimit: web3.utils.toHex(25000),
gasPrice: web3.utils.toHex(10e9), // 10 Gwei
to: addressTo,
from: addressFrom,
value: web3.utils.toHex(web3.utils.toWei(amount, 'wei'))
}
// Signs the given transaction data and sends it. Abstracts some of the details
// of buffering and serializing the transaction for web3.
const privateKey = new Buffer(privKey, 'hex')
const transaction = new Tx(txData)
transaction.sign(privateKey)
const serializedTx = transaction.serialize().toString('hex')
try {
return await web3.eth.sendSignedTransaction('0x' + serializedTx)
}catch(err) {
console.log(err.message);
return err.message;
}
//////////////////////////////
}
I hope someone could help me.
Best Regards.
TianYang
you can check in etherscan why the transaction fails. if the transaction worked last month, probably the problem is in the gas price. last week the gas prices were too high (safe low was 50 gwei) and I see that you are sending with 10gwei, this is most probably the reason why your transactions fail. Try increasing the gas price and see if it works again

How to get groups that user belong to?

Using Graph Service, I have tried to get list of groups that user belong to. Here is my sample code:
var userMemberOf = null;
var userMemberGroups = null;
const GraphService = require('graph-service');
const ClientCredentials = require('client-credentials');
const tenant = 'my-company.com';
const clientId = '0b13aa29-ca6b-42e8-a083-89e5bccdf141';
const clientSecret = 'lsl2isRe99Flsj32elwe89234ljhasd8239jsad2sl=';
const credentials = new ClientCredentials(tenant, clientId, clientSecret);
const service = new GraphService(credentials);
service.get('/users/tnguyen482#my-company.com/memberOf').then(response => {
userMemberOf = response.data;
});
var settings = {
"securityEnabledOnly": true
}
service.post('/users/tnguyen482#my-company.com/getMemberGroups', settings).then(response => {
userMemberGroups = response.data;
});
The data return from both get & post method was an empty list. I have tried another user id but the result is the same. Am I correct when using method memberOf and getMemberGroups to get list of groups that user belong to? Does my sample code correct?
When the user is in no group graph will return an empty result.
Otherwise, when an error occured (e.g. accessDenied or user not found) an corresponding http-status with an errormessage will be returned (more information in the documentation).
The operations you are using seem to be correct.
If you want to rule out that your operations/code is incorrect, you should try executing the operations in the Graph Explorer.
Its a great tool for debugging and you can even login for access to your own data.

Resources