Can't run UpdateDoc function when using Redux and FireBase - javascript

PersonalSlice.js
export const updatePersonal = createAsyncThunk("personal/updatePersonal", async (id, {getState})=>{
const personalDoc = doc(db, "Personal", id)
await updateDoc(personalDoc, getState().personal.updatePersonal );
});
Main.js
const updateName = useSelector((state) => state.personal.updatePersonal.name);
const handleUpdateNameChange = (e) => {
dispatch(changeUpdatePersonalName(e.currentTarget.value))
}
const handleUpdateSubmit = (e) => {
e.preventDefault();
dispatch(updatePersonal({updateName , updateSurname, updateBirthday, updateStartDate, updateDepartment, updatePhone, updateMail}))
}
<Form onSubmit={handleUpdateSubmit}>
<p className="text-center" style={{ color: "#39ace7" }}>İsim</p>
<Form.Control
size = "sm"
type="text"
name="updatePersonal"
onChange={handleUpdateNameChange}
value={updateName}
required
autoFocus
/>
I can't send the data I want to update in the form to FireBase. My fault is most likely in the parameters.

If you are starting a new project and/or are not required to have your Firebase data loaded into redux, you might want to give reactfire a try before trying react-redux-firebase. In reference to the above function call ,if the profile object contains a key or a list of keys as parameters, you can populate those parameters with the matching value from another location on firebase.
Setting config like this:
userProfile: 'users', // where profiles are stored in database
profileParamsToPopulate: [
'contacts:users'
]
}
Results in profile with populated contacts parameter:
displayName: 'ABC',
email: 'abc#xyz.com',
contacts: [
{
email: 'efg#xyz.com',
displayName: 'EFG'
},
{
email: 'pqr#xyz.com',
displayName: 'PQR
}
]
}
Please check the link here to understand the parameters call usage and related questions Update Data in Firebase and Update function in Firebase for reference.Also check the helpful documentation for configuration for redux-firebase

Related

Exclude certain attributes from object using the populate from mongodb using aggregate

I want to exclude for example email and address using populate() function from mongodb, just get the name from it:
Example:
const results = await Seller.aggregate(aggregatePipeline).exec();
const sellers = await Seller.populate(results, { path: "user" });
When populating the user instead of having:
...
user: {
email: "hgjh#gmail.com",
address:{},
name: "name"
}
I want to only have (exclude certain data from the path):
...
user: {
name: "name"
}
You can do either,
const sellers = await Seller.populate(results, { path: "user", select: '-
email -address' });
or
const sellers = await Seller.populate(results, { path: "user", select:
'name' });
As i understand mongoose documentation https://mongoosejs.com/docs/populate.html, populate as $lookup is use to resolve a relation with other collection.
MongoDB has the join-like $lookup aggregation operator in versions >= 3.2. Mongoose has a more powerful alternative called populate(), which lets you reference documents in other collections.
In your case, you don't need to resolve a field with an other collection. You already have the final data you target . You could use $project at the end of your pipeline aggregation to keep only name field, like :
{ $project: { name:1 } }
Let me know if i helped you.
Edit :
I read too fast, if you have this data res after the populate and not after the aggreg, you may select your final field, like is said
here https://stackoverflow.com/a/72481338/16205278
user: {
email: "hgjh#gmail.com",
address:{},
name: "name"
}

Many instances in one call to db (sequelize)

Someone knows how I can create an instance in sequelize and their associations in one call to db?
I want to say:
const user = await User.create({name: 'Tom'});
const project = await Project.create({title: 'Yes'});
await user.addProject(project);
Can i do this in a single function? Because if I want to bulkCreate many users and project, I have to call db a lot of times.
Thanks!
If the Models have an association then you can use the include property to specify the model and then pass in the data for the call to create(), see the params here: https://sequelize.org/master/class/lib/model.js~Model.html#static-method-create.
const user = await User.create(
{
name: 'Tom',
project: {
title: 'Yes',
},
},
{
include: {
model: Project,
},
}
);

What is type "StringQueryOperatorInput"? How can I get rid of this annoying graphql error?

I am attempting to create Gatsby pages programmatically using the Gatsby API createPages and data from Firebase. I've set up everything successfully up to the point where Firebase data is accessible via GraphQL and now I want to query specifict data for each of the new pages that were created using id (which are in string format). However, when I create the template component and try to query the data i get this error:
Variable "$clientId" of type "String!" used in position expecting type "StringQueryOperatorInput".
I have looked everywhere for a reference of this StringQueryOperatorInput and can't find any info on it. Google and graphql docs don't seem to mention the term and this is my first time seeing it. After troubleshooting for an hour I got a different error:
If you're e.g. filtering for specific nodes make sure that you choose the correct field (that has the same type "String!") or adjust the context variable to the type "StringQueryOperatorInput".
File: src/templates/Homeowner/Homeowner.js:24:9
However, I still don't know what a StringQueryOperatorInput is or how to fix this.
Below is my code for this component and my gatsby-node.js, and my gatsby-config.js where i use a plugin to source the Firebase data.
I could really use some help on this, I can't seem to find any reference of this StringQueryOperatorInput.
Everything else works fine, I just can't get this query on the Homeowner.js template to work.
gatsby-node.js
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const result = await graphql(`
query {
allClients {
nodes {
firstName
lastName
id
}
}
}
`);
console.log(JSON.stringify(result, null, 4));
result.data.allClients.nodes.forEach(node => {
const slug = `/client/${node.id}`;
createPage({
path: slug,
component: require.resolve(`./src/templates/Homeowner/Homeowner.js`),
context: { clientId: node.id },
});
});
};
src/templates/Homeowner/Homeowner.js
import React from 'react';
import { graphql } from 'gatsby';
import { withFirebase } from '../../components/Firebase';
import { withStyles } from '#material-ui/core/styles';
import Layout from '../../components/layout';
const Homeowner = ({ data }) => {
console.log(data.clients, 'data');
return (
<>
<Layout>
<h1>Home Owner Component</h1>
{/* <h3>{client.firstName}</h3>
<h3>{client.lastName}</h3>
<h3>{client.email}</h3> */}
</Layout>
</>
);
};
export default Homeowner;
export const query = graphql`
query($clientId: String!) {
clients(id: $clientId) {
firstName
lastName
email
}
}
`;
gatsby-config.js
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`,
});
module.exports = {
siteMetadata: {
title: `SiteTitle`,
siteUrl: `https://www.mysitwe.com`,
description: `YourSite`,
},
plugins: [
`gatsby-plugin-react-helmet`,
`gatsby-plugin-sitemap`,
`gatsby-plugin-styled-components`,
`gatsby-plugin-sharp`,
`gatsby-transformer-sharp`,
{
resolve: `gatsby-source-firebase`,
options: {
credential: require('./firebase-key.json'),
databaseURL: 'https://firebaseurl/',
types: [
{
type: 'Clients',
path: 'clients',
},
{
type: 'Users',
path: 'users',
},
],
},
},
{
resolve: `gatsby-plugin-prefetch-google-fonts`,
options: {
fonts: [
{
family: `Nunito Sans`,
variants: [`400`, `600`, `800`],
},
{
family: `Montserrat`,
variants: [`300`, `400`, `400i`, `500`, `600`],
},
{
family: `Spectral`,
variants: [`400`, `600`, `800`],
},
{
family: `Karla`,
variants: [`400`, `700`],
},
],
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-plugin-offline`,
],
};
THank you in advance if anyone can help me out.
Actually literally right after I posted this question I found the solution. I needed to set up my query like so:
export const query = graphql`
query($clientId: String!) {
clients(id: { eq: $clientId }) {
firstName
lastName
email
}
}
`;
I assume that leaving out the {eq: $clientId} throws that StringQuery error on the GraphQL side. I still do not know what a StringQueryOperatorInput is, however, I have successfully generated the pages with the data from firebase.
StringQueryOperatorInput is the type of the id argument of the clients field. GraphQL includes scalar types like String, ID or Int as well as types that describe more complex data structures like arrays or objects. In this case, StringQueryOperatorInput is an input object type -- it describes objects that can be used as inputs like argument values or variables.
When filtering fields, Gatsby uses an input object like this to enable using a variety of comparison operators to filter the exposed data -- in addition to eq (equals), you can use other operators like ne, regex, in, gt, etc. You can see the full list here. Because not all inputs apply to all scalars (regex makes sense for a String field but lte does not), there's a different input type for each scalar (IntQueryOperatorInput, BooleanQueryOperatorInput, etc.)
Gatsby exposes a GraphiQL endpoint in development. Writing queries using GraphiQL allows you to utilize autocomplete and syntax highlighting so that you can avoid unexpected syntax errors like this. You can also use the "Docs" button to search and browse the entire schema.

How do I find a specific path on the firebase realtime database then change the value at that path using a Text Input?

Pop quiz, hotshot:
You're building a react native app. You set some values to firebase as an object at the root of your app, like this:
firebase
.database()
.ref("/companies/")
.set({
awesomeCompany: {
name: "Awesome Company",
owner: "Joe Awesome",
gmail: "joeawesome#gmail.com",
fleetSize: 2
},
badCompany: {
name: "Bad Company",
owner: "Joe Bad",
gmail: "joebad#gmail.com",
fleetSize: 3
}
You want to give the current user a text input field through which they may change the fleetSize of a company if they are the owner of that company.
You have your firebase auth working properly, so you know that firebase.auth().currentUser.email will work to check against to determine if they are an owner.
Your database values have been set - they look like this:
{
"companies": {
"awesomeCompany": {
"fleetSize": 2,
"gmail": "joeawesome#gmail.com",
"name": "Awesome Company",
"owner": "Joe Awesome"
},
"badCompany": {
"fleetSize": 3,
"gmail": "joebad#gmail.com",
"name": "Bad Company",
"owner": "Joe Bad"
}
}
}
How would you render the initial information to the screen, and how would you set up the text input logic so that the user input changes data at the database?
To understand the brain I have, and how I'm failing, I'm including my own code below as a starting point. If there's a way to show me how I could take my basic strategy and make it work - even if it isn't elegant - I'd appreciate that. But overall I'm just really struggling with how to get data path references using Data Snapshot and keep them available to use elsewhere.
Thanks for your help, anyone!
// my crummy half baked code below
import React, { Component } from "react";
import { View, Text, TextInput, Button } from "react-native";
import { styles } from "../styles";
import * as firebase from "firebase";
export default class OwnerProfileScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
gmail: null,
name: null,
fleetSize: null
};
}
componentDidMount() {
this.getData();
}
getData = () => {
const rootRef = firebase.database().ref(); // firebase reference
const authEmail = firebase.auth().currentUser.email; // current user
return rootRef.once("value").then(
function(snapshot) {
const idArray = Object.keys(snapshot.child("companies/").val()); // array of Ids
const companyData = idArray.map(id =>
snapshot.child("companies/" + id).val()
); // values of contained in objects at each key
const ownersCompany = companyData.filter(
obj => obj.gmail === authEmail
); // an array containing one object if the gmail address in the object is the same as the currentUser logged in
// what is the path of fleetSize?
// how do I define it to keep it available to use later
// with a Text Input event?
this.setState({
name: ownersCompany[0].name,
gmail: ownersCompany[0].gmail,
fleetSize: ownersCompany[0].fleetSize
});
}.bind(this)
);
};
changeFleetSize = userInput => {
//in order to set the user input to the database, I need the path
//of the fleetSize of the current user (who has been verified as an
// owner by comparing firebase auth to gmail addresses of company)
};
render() {
return (
<View style={styles.container}>
<Text>minPrice = {this.state.name}</Text>
<Text>gmail = {this.state.gmail}</Text>
<Text>fleetSize = {this.state.fleetSize}</Text>
<TextInput
style={{ height: 40, borderColor: "gray", borderWidth: 1 }}
//onChangeText currently does nothing since I don't know how
// to get the particular path of particular fleetSize
onChangeText={userInput => this.changeFleetSize(userInput)}
/>
</View>
);
}
}
The code is quite messy so it's hard to say what you're trying to accomplish. But let me make a guess here:
You want to load a single company from your database.
You know the email address of the owner of the company.
If that is correct, you can use a query to accomplish the goal. Something like:
var query = rootRef.child("companies").orderByChild("gmail").equalTo(authEmail);
var self = this;
query.once("value").then(function(result) {
result.forEach(function(snapshot) { // loop over result snapshots, since there may be multiple
const companyData = snapshot.val();
self.setState({
name: companyData.name,
gmail: companyData.gmail,
fleetSize: companyData.fleetSize
});
})
);
The changes here:
Use a query to only select the companies with the correct gmail address.
Loop over the results, since (on an API level at least) there could be multiple companies with that value for their gmail property.
Get rid of the whole iterating over Object.keys and filtering, since that made it hard to read. This result is also more idiomatic for Firebase Realtime Database code.
Use self to track the this instance, just because I didn't feel like counting bind calls.

How to query linked documents in mongodb

I'd like to know if there's a way to directly search within a linked collection.
I'm using Express with mongoosejs
I have the following situation.
I have 3 collections, deal, product and store and I have associated product and store with the deal collection.
const DealSchema = new Schema({
...
product: {
type: Schema.Types.ObjectId,
ref: 'product'
},
shop: {
type: Schema.Types.ObjectId,
ref: 'shop'
},
...
});
In my collection product, I have a field called upc.
I have a controller that handles deals creation, however before I create a deal, I want to check whether or not there's already a deal with the same UPC in this store if so I'll only update the confirmedBy field.
This is my controller
async create(req, res) {
const dealProps = req.body;
const product = await Products.findOne({ upc: dealProps.upc });
let deal;
if (product) {
deal = await Deals.findOne({ product: product._id });
if (deal.shop.toString() === dealProps.shop.toString()) {
const updatedDeal = await Deals.findOneAndUpdate({ product: product._id }, {
$push: {confirmedBy: dealProps.user }
});
res.send(updatedDeal);
}
} else {
deal = await (new Deals(dealProps)).save();
res.send(deal);
}
}
I've tried to search directly within the product collection like this:
const product = await Deals.findOne({'product.upc': dealProps.upc });
However it returns null.
Is there a way to search directly within a linked collection? Do I need to create an index for the upc field in the product collection?
If not, should I rethink my deals collection to add the upc and storeId to simplify the lookup?
Thank you for your help, much appreciated.

Categories