Unexpected error when querying for a field from Firebase - javascript

I am using React.js to query a field in a document from Firebase. However, when I try to get the data, I keep getting an error. The code, the collection on Firestore, and and the error message are below. How do I properly query specific fields of data without running into this error?
import React from 'react';
import styled from 'styled-components';
import { firestore } from '../../firebase/firebase.utils';
class Economics extends React.Component {
constructor() {
super();
this.state = {
name: firestore.collection('blog-categories').doc('8uVaHd22tT5oXSzpOOuj').get('name')
}
}
render() {
return (
<div>
hi
</div>
)
}
}
export default Economics;

I think this is proper reference for the API you are using.
When you enter parameter to get method API is expecting options object, so when you enter String "name" there you will get this error massage.
The method is asynchronous so you have to take value form DocumentSnapshot (reference) object returned as Promise which result of the method.
I hope it will help!
UPDATE: As requested I'm adding example:
Firestore has collection collection1 with document doc1 that has field field1 with value 'value1':
var Firestore = require('#google-cloud/firestore');
var db = new Firestore();
var docRef = db.collection("collection1").doc("doc1");
docRef.get().then(docSnap => {
console.log(docSnap.data().field1);
console.log(docSnap.get("field1"));
});
If you run this in node result is:
value1
value1

Related

how to handle the async data in vue3

I have the deman to fetch the server data and then process before rendering the page.
here is the code in my index.vue, in option api:
<template>
<div>{{userData.name}}</div>// đź’—'helloworld'
<div>{{testName}}</div>// ❌'undefined'
</template>
<script>
import {ref} from 'vue'
import axios from 'axios'
export default{
setup(){
const userData=ref([])
const testName = ref('')
oNmounted(async ()=>{
const res=await axios({url:'/myProfile',method:'get'})
})
userData.value=res.data.data //here I can get the async data after the Internet time travel.
//in other func to process the `userData` object which would be `[{name:'helloWorld',...}]
testName.value = userData.name
cosole.log(userData.name) //output `undefined`, but if i refer it in the template section, it works.
}
return {
userData,
testName,
}
}
</script>
I want to process the async data before it is rendered, how can I make sure that I could obtain the fetched data to use in the <script> section instead of <template> section?
And the userData I defined is a ref, in the beginnig of the async fetch, it is assumed to be undefined, but after the async axios, the userData is assinged to the latest target value I want, then why they won't be updated accordingly?
what am I missing in this fulfillment?
You defined userData as a ref (see https://vuejs.org/api/reactivity-core.html#ref)
const userData = ref([])
When you want to access the value of userData inside your code block, you need to use the property .value to points to the inner value.
If access is in the template tag, don't use the .value property.
So the corrected line would be :
testName.value = userData.value.name

firebase.firestore.FieldValue.delete() not deleting field in document

I'm trying to delete a field in a Firebase document from a React app using firebase.firestore.FieldValue.delete() but it isn't working. Reading and writing data to documents and collections is working fine but I am struggling to get FieldValue to work. I've set up the Firebase instance in src/firebase.js like this:
import app from 'firebase/app';
import 'firebase/firestore';
var config = {
******
};
class Firebase {
constructor() {
app.initializeApp(config);
this.fv = app.firestore.FieldValue;
this.db = app.firestore();
};
};
export default Firebase;
And then in the module that I am trying to use FieldValue in I am doing:
import Firebase from "./firebase.js";
class App extends Component {
constructor(props) {
super(props);
this.firebase = new Firebase();
this.db = this.firebase.db;
this.fv = this.firebase.fv;
};
deleteFunction(id) {
this.db.collection("collection_id").doc("doc_id").update({
field_id: this.fv.delete()
});
}
};
However no variation of imports or doc references as mentioned here have been successful for me. I don't receive any errors and I know that the firestore instance is working correctly because I am using it to set and read the same data. I have also verified that the field_id I am trying to delete is the correct id and that this.fv is FieldValue by console logging them both.
What am I missing? I feel like this should be super easy and straight forward and that I am overlooking something super obvious,
My guess is that you're trying to delete the field that is identified by field_id, so say:
// THIS WON'T WORK
let field_id = "fieldToDelete";
this.db.collection("collection_id").doc("doc_id").update({
field_id: this.fv.delete()
})
The above code is trying to delete the literal field_id field, which probably doesn't exist.
You'll need to use [] notation to build the object you pass to Firestore.
let field_id = "fieldToDelete";
let updates = {};
updates[field_id] = this.fv.delete()
this.db.collection("collection_id").doc("doc_id").update(updates)
Now you're using the value of field_id in the call to Firestore, and it will delete fieldToDelete.

Trying to pass parameter with graph ql query getting an error

I have below graphl api query that i am using to send the data from react front app with the object to get the desired results
{
allSectionRequests(data:{
requestStageName:"Request Submitted"
}){
section
type
}
}
and then i am trying to pass variable from react like below
export const GET_SECTIONREQUESTS = gql`
query AllSectionRequests($data: sectionRequestParamsInput){
allSectionRequests(data: $data){
section
type
}
}
`;
I have attached the image that i need to send to graphql api below
and the below is the react code that i will be calling query inside component and then passing data object to graphql api
const { data: dashBoardData, loading: dashBoardDataLoading, error: dashBoardDataError } = useQuery(GET_SECTIONREQUESTS, {
variables: { data: { requestStageName: 'Request Submitted' } },
});
I am getting error like this below
The variable **data** type is not compatible with the type of the argument **data**.
↵Expected type: SectionRequestParamsInput.
i am not sure where i am doing wrong with this code, could any one please help on this one .
Many thanks
I have rectified my problem with the below solution
export const GET_SECTIONREQUESTS = gql`
query AllSectionRequests($sectionRequestParamsInput: SectionRequestParamsInput){
allSectionRequests(data: $sectionRequestParamsInput){
id
section
type
createdBy
description
status
age
}
}
`;
and then changed my input parameters in react like this
const { data: dashBoardData, loading: dashBoardDataLoading, error: dashBoardDataError } = useQuery(GET_SECTIONREQUESTS, {
variables: { sectionRequestParamsInput: { requestStageName: 'Request Submitted' } },
});
i hope this will helps to any person who is looking for graphql api query with parameters passed in.

Change value of field in reactjs component's state (with data obtained from firebase)

I simply want to fetch a string from a Firebase database and update the "eventName" field in my component, but I'm having trouble doing this.
My code so far:
import React from 'react';
import {ref} from '../Firebase';
class EventDisplay extends React.Component {
constructor () {
super();
this.state = {
eventName: "No event Selected."
};
}
render () {
return (<div>
<h1>Name of Event: {this.state.eventName}</h1>
<h1>Date and Time: Dummy Name</h1>
<h1>Event Description: Dummy Name</h1>
</div>);
}
changeEventName(str) {
this.setState({eventName: str});
}
componentWillMount() {
const events = ref.child('events/event1/Title');
var param;
events.on('value', (function(snapshot) {
param = snapshot.val();
console.log(snapshot.val());
changeEventName(param);
})
);
console.log(param);
}
}
export default EventDisplay;
However, changeEventName seems to be undefined where it is. Also "undefined" shows up in the console where I try to log param, but snapshot.val() has the desired string.
Thanks
changeEventName seems to be undefined where it is
Where you're calling changeEventName you need to prepend it with this.
this.changeEventName
Also since you're calling it inside of a callback you first need to bind the method in order to preserve the value of this. There're many ways you can do this, most common being:
Explicitly inside of a constructor:
this.changeEventName = this.changeEventName.bind(this)
Or using an arrow function:
events.on('value', ((snapshot) => { ... }));
Also "undefined" shows up in the console where I try to log param
That's because events.on is asynchronous, you need to move your console.log inside of the callback.
Try this.changeEventName when invoking the function; you need to do this because the function is available only within the context of the class.
Logging param returned undefined because events.on is an asynchronous function. What that means is that this function will go do whatever it was designed to do (fetch value) and only then execute the callback when its ready; param is only available in this callback method that you provided.

Creating a altjs flux store for fetching data from API

I'm stuck trying to figure out how to write a flux store and action that works in just fetching data from my express API using altjs
import $ from 'jquery';
const utils = {
myProfile: () => {
return $.ajax({
url: '/myProfile',
type: 'GET'
});
}
};
This is how I believe I should write my GET request for just grabbing a user's profile (which should return a json with user info).
then for my store :
import UserActions from 'actions/UserActions';
import alt from 'altInstance';
class UserStore {
constructor() {
this.userProfile = [];
this.on('init', this.bootstrap);
this.on('bootstrap', this.bootstrap);
this.bindListeners({
fetchUserProfile: UserActions.FETCHUSERPROFILE,
});
}
fetchUserProfile(profile) {
this.userProfile = profile;
}
}
export default alt.createStore(UserStore, 'UserStore');
However the action is where i'm the most clueless
import alt from 'altInstance';
import UserWebAPIUtils from 'utils/UserWebAPIUtils';
fetchProfile(){
this.dispatch();
UserWebAPIUtils.getProfile()
//what do we do with it to let our store know we have the data?
});
}
}
}
All im trying to do, is grab data from the server, tell my store we've recieved the data and fill the userprofile array with the data from our api, and the messenger for telling our store is through a dispatcher which belongs to 'actions' correct? I've looked at a lot of tutorials but I still dont feel very confident on how I am thinking about this. What if I wanted to update data through a POST request what would that be like?
Looking through altjs doc it seems like they recommend doing the async operations from actions. I prefer this approach as well because it keeps stores synchronous and easy to understand. Based on their example
LocationAction
LocationsFetcher.fetch()
.then((locations) => {
// we can access other actions within our action through `this.actions`
this.actions.updateLocations(locations);
})
.catch((errorMessage) => {
this.actions.locationsFailed(errorMessage);
});
Basically they are fetching the information and then triggering 2 actions depending on the result of the request which the store is listening on to.
LocationStore
this.bindListeners({
handleUpdateLocations: LocationActions.UPDATE_LOCATIONS,
handleFetchLocations: LocationActions.FETCH_LOCATIONS,
handleLocationsFailed: LocationActions.LOCATIONS_FAILED
});
When the store receives a handleUpdateLocations action which happens when the fetcher returns successfully. The store will update itself with new data and dispatch
handleUpdateLocations(locations) {
this.locations = locations;
this.errorMessage = null;
}
With your code you can do something similar. The fetch user profile will be triggered when data is originally requested. Here I am setting user profile to be [] which is your original init value but you can set it to anything to indicate data is being loaded. I then added 2 more methods, handleFetchUserProfileComplete and handleFetchUserProfileError which get called depending on if your fetch was successful or not. The code below is a rough idea of what you should have.
constructor() {
this.userProfile = [];
this.on('init', this.bootstrap);
this.on('bootstrap', this.bootstrap);
this.bindListeners({
handleFetchUserProfile: UserActions.FETCH_USER_PROFILE,
handleFetchUserProfileComplete: UserActions.FETCH_USER_PROFILE_COMPLETE,
handleFetchUserProfileError: UserActions.FETCH_USER_PROFILE_ERROR,
});
}
fetchUserProfile() {
this.userProfile = [];
}
handleFetchUserProfileComplete(profile) {
this.userProfile = profile;
}
handleFetchUserProfileError(error) {
this.error= error;
}
export default alt.createStore(UserStore, 'UserStore');
The only thing left is to trigger these 2 actions depending on the result of your fetch request in your action code
fetchUserProfile(){
this.dispatch();
UserWebAPIUtils.getProfile().then((data) => {
//what do we do with it to let our store know we have the data?
this.actions.fetchUserProfileComplete(data)
})
.catch((errorMessage) => {
this.actions.locationsFailed(errorMessage);
});
}
fetchUserProfileComplete(profile) {
this.dispatch(profile);
}
fetchUserProfileError(error) {
this.dispatch(error);
}

Categories