receive specific data from Firebase with if statement in React Native - javascript

I am new with Firebase and React Native. I have created a database and now that when a certain number is equal to a number in 1 of the objects in firebase, it stores this data in an array.
I have the following code for that:
scanOutput = '0';
getUserData = () => {
console.log(this.scanOutput);
let ref = firebase.database().ref('Questions/1R1/NL');
ref.on('value' , snapshot =>{
var state = snapshot.val();
console.log(state);
if('1' === this.scanOutput){
this.setState({questions: state});
}
})
}
componentDidMount(){
this.scanOutput = this.props.navigation.getParam('output');
this.getUserData();
}
the database looks like this:
Currently the if statement contains a "1" hardcoded, what I want to achieve is that when this.scanOutput (in this case "1") equals "question_number" from the database, it places all data in the state.

Your code is reading all data under Questions/1R1/NL. Since there may be multiple questions under there, the snapshot may contain multiple child nodes. Your callback needs to handle those by looping over snapshot.forEach.
Something like this:
let ref = firebase.database().ref('Questions/1R1/NL');
ref.on('value' , snapshot =>{
snapshot.forEach((question) => {
var state = question.val();
if(state.question_number === this.scanOutput){
this.setState({questions: state});
}
})
})

If snapshot returns you an object then you can destructure it:
const { question_number } = snapshot.val();
console.log(question_number);
then you can have a check like:
if(question_number === this.scanOutput){

Related

How to use firebase onSnapshot in chain using JavaScript?

I want to use firebase's onSnapshot function sequentially. A situation where I want to apply this is given below.
Scenario:
There are 2 collections in firestore. Employees and Projects. In the Employees collection, the docs are storing the details of employees. And it also stores the IDs of Projects docs on which that particular employee is working. In Projects collection, the detail of projects is stored.
Goal:
First, I have to fetch the data from Employees collection related to a specific employee. Then, from the fetched employee data, I will have the project IDs on which he/she is working on. So, from that ID I need to fetch the project details. So, when any information related to project or employee changes, the data on screen should also change in real-time.
Issue:
I tried to write a nested code. But it works realtime only for employee data. It doesn't change when the project detail is updated. Something like this...
admin.auth().onAuthStateChanged(async () => {
if (check_field(admin.auth().currentUser)) {
await db.collection('Employees').doc(admin.auth().currentUser.uid).onSnapshot(snap => {
...
let project_details = new Promise(resolve => {
let projects = [];
for (let i in snap.data().projects_list) {
db.collection('Projects').doc(snap.data().projects_list[i]).onSnapshot(prj_snap => {
let obj = prj_snap.data();
obj['doc_id'] = prj_snap.id;
projects.push(obj);
});
}
resolve(projects);
});
Promise.all([project_details]).then(items => {
...
// UI updation
});
...
});
}
});
What is the correct way for doing this?
You're actually proposing a pretty complex dataflow scenario. I would approach this as a multi-step problem. Your goal is essentially:
If there is a user, listen in realtime for the list of project ids for that user.
For each project id, listen in realtime for details about that project.
(presumably) Clean up listeners that are no longer relevant.
So I would tackle it something like this:
let uid;
let employeeUnsub;
let projectIds = [];
let projectUnsubs = {};
let projectData = {};
const employeesRef = firebase.firestore().collection('Employees');
const projectsRef = firebase.firestore().collection('Projects');
firebase.auth().onAuthStateChanged(user => {
// if there is already a listener but the user signs out or changes, unsubscribe
if (employeeUnsub && (!user || user.uid !== uid)) {
employeeUnsub();
}
if (user) {
uid = user.uid;
// subscribe to the employee data and trigger a listener update on changes
employeeUnsub = employeesRef.doc(uid).onSnapshot(snap => {
projectIds = snap.get('projects_list');
updateProjectListeners();
});
}
});
function updateProjectListeners() {
// get a list of existing projects being listened already
let existingListeners = Object.keys(projectUnsubs);
for (const pid of existingListeners) {
// unsubscribe and remove the listener/data if no longer in the list
if (!projectIds.includes(pid)) {
projectUnsubs[pid]();
delete projectUnsubs[pid];
delete projectData[pid];
render();
}
}
for (const pid of projectIds) {
// if we're already listening, nothing to do so skip ahead
if (projectUnsubs[pid]) { continue; }
// subscribe to project data and trigger a render on change
projectUnsubs[pid] = projectsRef.doc(pid).onSnapshot(snap => {
projectData[pid] = snap.data);
render();
});
}
}
function render() {
const out = "<ul>\n";
for (const pid of projectIds) {
if (!projectData[pid]) {
out += `<li class="loading">Loading...</li>\n`;
} else {
const project = projectData[pid];
out += `<li>${project.name}</li>`;
}
}
out += "</ul>\n";
}
The above code does what you're talking about (and in this case the render() function just returns a string but you could do whatever you want to actually manipulate DOM / display data there).
It's a lengthy example, but you're talking about a pretty sophisticated concept of essentially joining realtime data dynamically as it changes. Hope this gives you some guidance on a way forward!

How to use cloud function trigger based on two collections documents

I have a collection ReferalCodes in which each document is specified has these values where 'mine' value is false 'msg' value is false and mycode is user referal codes.
appliedcode: ""
mine:false
msg:false
mycode:"ASDF4G"
referals : []
And User has one more collection UserTransaction which have a field 'CountTrans' which is initialized as 0 when this value is 1 i want to trigger a function to check value of mine and appliedcode if the value of mine is true then and applied code have value of length 6 then i want to update the UserTransaction of that user and the appliedcode is referal code of some another user want to change UserTransaction of that user also
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const { user } = require('firebase-functions/lib/providers/auth');
admin.initializeApp();
const db = admin.firestore();
exports.getCount= functions.firestore
.document('UserTransactions/{id}')
.onUpdate((change, context) => {
const newTransdata = change.after.data();
const previousTransData = change.before.data();
const docid = context.params.docid;
if(newTransdata.CountTrans === 1) {
const referalData = await
admin.firestore.collection('ReferalCodes').doc(docid).get()
const mine = referalData.mine;
const appliedCode = referalData.appliedCode;
let codes = [];
var myfrindid;
if(mine === true && appliedCode !== null) {
const friendData = await
admin.firestore.collection('ReferalCodes').doc('codes').get();
var referalcodes = friendData['ReferalCodes'];
referalcodes.forEach((items) =>{
if (items['code'] == appliedCode) {
myfrindid = items['id'];
}
});
await
admin.firestore.collection('ReferalCodes').doc(docid).update({
msg: true
})
}else{
}
}
});
Consulting the official documents is explained how to handle events on your database and trigger some different kind of triggers depending on your needs, for example:
onWrite(), which triggers when data is created, updated, or deleted in Realtime Database.
onCreate(), which triggers when new data is created in Realtime Database
onUpdate(), which triggers when data is updated in Realtime Database
onDelete(), which triggers when data is deleted from Realtime Database
For example, the first argument passed your onUpdate handler function is a Change object, this object has two properties, before and after, both DataSnapshot objects. These DataSnapshot objects describe the contents of the database before and after the change that triggered the function.
exports.foo = functions.database.ref('/location-of-interest')
.onUpdate((change) => {
const before = change.before // DataSnapshot before the change
const after = change.after // DataSnapshot after the change
})

Delete a array element from a Firestore database

I'm trying to delete an element from an array in a Firestore document. However, none of the approaches I tried had worked so far. My last attempt was like this:
const ref = firestore().collection('events').doc(extraid);
ref.get().then(document => {
const thing = document.data();
const rejected = thing.rejected || [];
const interested = thing.interested || [];
const fieldIndex = interested.findIndex(obj => obj.interestedId === sender);
const fieldToDelete = interested[fieldIndex];
firebase.firestore.FieldValue(fieldToDelete);
firebase.firestore.FieldValue.delete(fieldToDelete);
});
How can I delete an element from an array in a Firestore document?
You will have to update() the modified array field back to the document as suggested by the documentation. Calling FieldValue.delete() isn't enough - that just creates a FieldValue token that you can pass to update() to make the change. It will look something like this:
ref.update('interested', FieldValue.delete(fieldToDelete))

Get the ChildrenCount of a child in Firebase using JavaScript

I have been doing this for an hour. I simply want to get the number of children in the child "Success" in the database below. The answers in similar stackoverflow questions are not working. I am new in Javascript Programming.
So far I have tried this
var children = firebase.database().ref('Success/').onWrite(event => {
return event.data.ref.parent.once("value", (snapshot) => {
const count = snapshot.numChildren();
console.log(count);
})
})
and also this
var children = firebase.database().ref('Success/').onWrite(event => {
return event.data.ref.parent.once("value", (snapshot) => {
const count = snapshot.numChildren();
console.log(count);
})
})
Where might I be going wrong.
As explained in the doc, you have to use the numChildren() method, as follows:
var ref = firebase.database().ref("Success");
ref.once("value")
.then(function(snapshot) {
console.log(snapshot.numChildren());
});
If you want to use this method in a Cloud Function, you can do as follows:
exports.children = functions.database
.ref('/Success')
.onWrite((change, context) => {
console.log(change.after.numChildren());
return null;
});
Note that:
The new syntax for Cloud Functions version > 1.0 is used, see https://firebase.google.com/docs/functions/beta-v1-diff?authuser=0
You should not forget to return a promise or a value to indicate to the platform that the Cloud Function execution is completed (for more details on this point, you may watch the 3 videos about "JavaScript Promises" from the Firebase video series: https://firebase.google.com/docs/functions/video-series/).
const db = getDatabase(app)
const questionsRef = ref(db, 'questions')
const mathematicalLiteracy = child(questionsRef, 'mathematicalLiteracy')
onValue(mathematicalLiteracy, (snapshot) => {
const data = snapshot.val()
const lenML = data.length - 1
console.log(lenML)
})
This method worked for me. I wanted to get the children's count of the mathematicalLiteracy node in my database tree. If I get its value using .val() it returns an array that contains that node's children and an extra empty item. So, I subtracted that one empty item's count. Finally, I get my needed children's count.

Pass value from map to state

//It's working now - updated code
I'm working on my own autocomplete component because I have problem with passing firebase data to a ready one.
The whole mechanism is working good but I have problem with passing values after getting user input
I'm setting initial state with those values
const INITIAL_STATE = {
allChars: [],
suggestions: [],
value: ""
};
Then in autocomplete class i'm loading all users from database
loadData(){
let self = this;
let characters = firebase.firestore().collection("users");
characters.get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
let document = doc.data();
self.setState(({allChars})=>({
allChars: [
...allChars,
document
]
}))
});
});
}
Here is my getSuggestions function. It is firing on input change
getSuggestions = event => {
const {value, suggestions} = event.target;
this.setState({
value: value,
suggestions: []
})
let suggest = [];
this.state.allChars.map((allChars) => {
if(value.length > 1 && allChars.name.toLowerCase().includes(value.toLowerCase())){
suggest.push (
allChars.name
);
}
})
this.setState({
suggestions: suggest
})
}
In render I just put {sugestions}
But in {suggestions} I get rendered only one name.
one
But when I console.log it - I get two names
two
There should be two.
I tried to set state in this function like in loadData(), but I still get only one value.
Is there other way to get both values into DOM
Full code can be found here: https://github.com/Ilierette/react-planner/blob/master/src/component/elements/Autocomplete.js
I think the reason you are just seeing one element each time your components re-render is that in your map function on your allChars array, when you want to update the suggestions in your state, you are setting just the name each time as a new array while you should update the existing array in your state, so your code should be:
this.setState({
suggestions: [...this.state.suggestions, allChars.name]
})

Categories

Resources