Firebase React (native) get documents by reference field - javascript

I have created 3 tables in firebase console. Event, occurrence and venue. Now an event can have multiple occurrences, as occurrences are basically shows.
In occurrence document I have event set as reference and venue set as reference.
I query firebase through occurrence to get all the latest shows.
I want to build an array of javascript objects in react that will have id, date (comes from occurrence), title (comes from event) and address (comes from venue).
const [events, setEvents] = useState<any[]>([]);
useEffect(() => {
const subscribe = firestore()
.collection('occurrences')
.onSnapshot(querySnapshot => {
const showList: any[] = [];
querySnapshot.forEach(documentSnapshot => {
const { startDate, event, venue } = documentSnapshot.data();
const show: any = {
id: documentSnapshot.id,
date: startDate,
};
event.onSnapshot(
eventsDocSS => {
show.title = eventsDocSS.get('name');
},
error => console.error('my error', error)
);
venue.onSnapshot(
eventsDocSS => {
show.address =
eventsDocSS.get('addressLocality') + ', ' + eventsDocSS.get('addressRegion');
},
error => console.error('my error', error)
);
showList.push(show);
});
setEvents(showList);
});
return subscribe()
},[])
This code mind you does not work as I would need to run the event and venue snapshots async to make it work. But if I make it async I have cascade it all the way out at least to forEach loop, which does not work as subscribe cannot be async.
I am using #react-native-firebase/firestore but the code should not be that different in syntax.
How do I get setEvents populated with correct data?

Related

Trouble accessing firebase query results in document template

new to vue and firebase but stuck on this for hours. I have a vue3 app running a specific firebase9 query that will only return a maximum of 1 row (i.e. includes limit 1). The results are being returned but I am having trouble accessing the data so I can pass up to the template. I am using an example from a tutorial that was designed to return multiple rows from FB then iterate through in the template using v-for but in this case it will only ever be one row. All the tutorials I can find are similar not addressing how to deal with one row (or document) being returned. Oddly, the data is being returned to _rawValue but I can't seem to get to it...
Here's the JS snippet:
let collectionRef = collection(db, c)
collectionRef = query(collectionRef, where(...q), orderBy(...ob), limit(...lmt))
const unsub = onSnapshot(collectionRef, snapshot => {
let results = []
snapshot.docs.forEach(doc => {
results.push({ ...doc.data(), id: doc.id })
})
// update values
documents.value = results
})
return { documents }
Here's the Vue snippet:
const { documents: lastEvent } = getCollectionRt(
'events',
['userId', '==', user.value.uid],
['created', 'desc'],
['1']
)
console.log('lastevent: ', lastEvent)
I can see that lastEvent does indeed contain an array with the values I am looking for so the query is running and returning, BUT, it is listed in something called "_rawValue" that I can't seem to access. For example I would like to set a variable to one of the values being returned like let myVar = lastEvent.id or lastEvent.created, etc.
[edit: use case is that I want to query the users last input so I that can set some of the form data default values based on their last entry]
Any help or reference to get me unstuck would be greatly appreciated.
Screenshot of console.log
Came up with a solution. Probably hacky but works.
First modify the getCollectionRt.js that runs the query as
...
const document = ref(null)
collectionRef = query(collectionRef, where(...q), orderBy(...ob), limit(...lmt))
const unsub = onSnapshot(collectionRef, snapshot => {
let results = []
snapshot.docs.forEach(doc => {
results.push({ ...doc.data(), id: doc.id })
document.value = { ...doc.data(), id: doc.id }
})
// update values
documents.value = results
})
return { documents, document }
then pull in 'document' and return in vue as:
const { documents: lastEvent, document } = getCollectionRt(
'events',
['userId', '==', user.value.uid],
['created', 'desc'],
['1']
)
...
return {..., document }
then I can access it in the template as {{ document.id}}
Although this works, definitely spend more time learning about workign with object/arrays in VueJS

FirebaseError: Expected type 'Hc', but it was: a custom Yc object]

i am trying to do a batch entry, but this error keeps occurring.
i am passing an array in a .doc, it works fine on other function, where i pass an array into .doc using loops and functions.
please help me out and please explain me what the error means.
export const AddTaskToFriend = (
ArryOfIds,
email,
title,
tag,
prayority,
completed
) => {
return async (dispatch) => {
const db = firebase.firestore();
var batch = db.batch();
for (let i = 0; i < ArryOfIds.length; i++) {
const Collections = db
.collection("Tasks")
.doc(ArryOfIds[i])
.collection("SingleTask");
batch.set(Collections, {
creater: firebase.auth().currentUser.uid,
UpdatedOn: new Date().toString(),
CreatedOn: new Date().toString(),
email,
title,
tag,
prayority,
completed,
});
}
batch
.commit()
.then((success) => {
console.log(` its a success ${success}`);
})
.catch((error) => {
console.log(error);
});
It looks like the error could come from batch.set(). As per this documentation .set() needs a reference to a document, and in your case you are passing a collection reference:
const Collections = db
.collection("Tasks")
.doc(ArryOfIds[i])
.collection("SingleTask");
You could try adding .doc() after .collection("SingleTask") to see if this solves the issue.

Trying to subscribe to a specific event on ETH using Web3, but not sure how to retrieve the returned data and use it

I'm trying to build a Javascript Bot subscribing to specific events on a contract, I have written some lines of code but I'm not sure how the EventEmitter returns data and how I can use it. Can anyone give me an example on how I can retrieve specific data (like transaction hash/ parameters of the event) each time web3.eth.subscribe() fires ?
Here's the code I've written :
const Web3 = require('web3')
const web3 = new Web3(new Web3.providers.HttpProvider("https://api.avax-
test.network/ext/bc/C/rpc") )
web3.eth.subscribe(
'logs',
{
address : 'some contract address',
topics : ['Keccak-256 hash(the event)']
},
function(error,result){
if(!error)
console.log(result);
}
)
.on("connected",function(subscriptionId){ //to check if subscription is successful
print(subscriptionId);
})
If you listen to contract events like this, they will not have any parameters in the returned object. Instead, if you need the parameters you need to get the events from the contract object. There are two options (example shows how to get the "Transfer" events)
Option one
let options = {
filter: {
value: ['1000', '1337'] //Only get events where transfer value was 1000 or 1337
},
fromBlock: 0, //Number || "earliest" || "pending" || "latest"
toBlock: 'latest'
};
const myContract = new Web3.Contract(ABI, CONTRACT_ADDRESS);
myContract.getPastEvents('Transfer', options)
.then(results => console.log(results))
.catch(err => throw err);
Option two
let options = {
filter: {
value: [],
},
fromBlock: 0
};
const myContract = new Web3.Contract(ABI, CONTRACT_ADDRESS);
myContract.events.Transfer(options)
.on('data', event => console.log(event))
.on('changed', changed => console.log(changed))
.on('error', err => throw err)
.on('connected', str => console.log(str))
source: https://www.coinclarified.com/p/3-ways-to-subscribe-to-events-with-web3-js/

React Native Firebase adding and getting data

wondering if anyone can assist me in this matter. I'm following the documentation for https://rnfirebase.io/firestore/usage. it does not work for my use case for some reason.
I just need to set the data, which it works and then read it back so i can push it onto my state and i'll render it.
I just can't read the data back properly. This addItemFunction is trigger when when user click on a button to add.
const addItemFunction = async (numb,exercise) =>{
firestore().collection(userEmail).get().then((snap) =>{
if(!snap.empty){
var finalID = uuid.v4();
firestore().collection(userEmail).doc(final).update({
[finalID]:{
exe:[exercise],
num:[numb],
}
}).then(() =>{
//RETURN SNAPSHOT NOT WORKING
console.log('user_added');
firestore().collection(userEmail).doc(final).onSnapshot(documentSnapshot =>{
console.log("here" + documentSnapshot.data());
});
}
Thanks for your time.
If you are using react with hooks I would suggest you put the onSnapshot listener in a useEffect hook:
useEffect(() => {
const unsubscribe = firestore
.collection(collectionName)
.doc(docId)
.onSnapshot(
(documentSnapshot) => {
const document = documentSnapshot.data();
console.log(document)
},
(error: Error) => {
throw error;
}
);
return () => unsubscribe();
}, [ docId, collectionName]);
this approach will separate concerns and the snapshots will run every time there is a change on the document, then where I put the console.log you could set the document to state.
Another approach will be to use get() instead of onSnapshot like:
const addItemFunction = async (numb,exercise) =>{
firestore().collection(userEmail).get().then((snap) =>{
if(!snap.empty){
var finalID = uuid.v4();
firestore().collection(userEmail).doc(final).update({
[finalID]:{
exe:[exercise],
num:[numb],
}
}).then(() =>{
console.log('user_added');
firestore().collection(userEmail).doc(final).get().then(() => {
console.log("here" + documentSnapshot.data());
})
}
}
}
this approach will not subscribe to changes and it will return the new updated document every time you call the addItemFunction

[TypeError]: Firebase orderByChild not working

I'm trying to query my database such that it retrieves an ordered list based on each child key. I do it as follows (see below), but "TypeError" happens. That is ordered at random when using .on('value', snapshot =>. I can't fix that, do you guys have any ideas to realize?
The Error
TypeError: In this environment the sources for assign MUST be an object. This error is a performance optimization and not spec compliant.
Realtime Database Query
Source Code
export const messagesFetch = (room) => {
return (dispatch) => {
firebase.database().ref(`/rooms/${room.roomId}/messages`)
.once('child_added', snapshot => {
dispatch({ type: 'messages_fetch_success', payload: snapshot.val() });
})
};
};
child_added will create a new snapshot for each message, instead of returning a list of messages in one object.
You might want to look at .once('value') instead of once('child_added').
As you wanted an ordered list I added the query orderByKey() which will return the messages in key order.
export const messagesFetch = (room) => {
return (dispatch) => {
firebase.database().ref(`/rooms/${room.roomId}/messages`)
.orderByKey()
.once('value')
.then(snapshots => {
snapshots.forEach(snapshot => {
dispatch({ type: 'messages_fetch_success', payload: snapshot.val() });
return false;
});
});
};
};
Is a react-native app, right?! If yes add a flag in question.
In firebase 'child_added' fires for each child and ever a new child has add, like sketchthat says. With 'once' you not listen the node, but, because 'child_added' you fires your function for every child. In other words your function return differents values (snapshot) for a same constant.

Categories