reactjs - Formik、Material UI Autocomplete 和 Firestore - 在哪里查询以查找数组参数
问题描述
您如何修改 formik onChange 处理程序,以便它只保存传递给 Material UI 自动完成字段的选项的值(而不是值加标签的数组)?
我有一个集合,其中包含一个名为 category 的属性的文档。目前,该类别使用表单输入选项中的标签和值填充。
我正在努力寻找一种方法来获取 firebase where 查询以查找数组的 value 属性。
我想知道如果我尝试将值而不是标签和值都保存到firestore中,我是否会更接近一个可行的解决方案。
我有一个 Formik 表格:
import React, { useState } from "react";
import ReactDOM from "react-dom";
import {render} from 'react-dom';
import { Link } from 'react-router-dom';
import firebase, {firestore} from '../../../firebase';
import { withStyles } from '@material-ui/core/styles';
import {
Button,
LinearProgress,
MenuItem,
FormControl,
Divider,
InputLabel,
FormControlLabel,
TextField,
Typography,
Box,
Grid,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from '@material-ui/core';
import MuiTextField from '@material-ui/core/TextField';
import {
Formik, Form, Field, ErrorMessage, FieldArray,
} from 'formik';
import * as Yup from 'yup';
import {
Autocomplete,
ToggleButtonGroup,
AutocompleteRenderInputParams,
} from 'formik-material-ui-lab';
import {
fieldToTextField,
TextFieldProps,
Select,
Switch,
CheckboxWithLabel,
Checkbox
} from 'formik-material-ui';
const allCategories = [
{value: 'health', label: 'Health & Medical'},
{value: 'general', label: 'General'},
];
function UpperCasingTextField(props: TextFieldProps) {
const {
form: {setFieldValue},
field: {name},
} = props;
const onChange = React.useCallback(
event => {
const {value} = event.target;
setFieldValue(name, value ? value.toUpperCase() : '');
},
[setFieldValue, name]
);
return <MuiTextField {...fieldToTextField(props)} onChange={onChange} />;
}
function Summary(props) {
const { classes } = props;
const [open, setOpen] = useState(false);
const [isSubmitionCompleted, setSubmitionCompleted] = useState(false);
function handleClose() {
setOpen(false);
}
function handleClickOpen() {
setSubmitionCompleted(false);
setOpen(true);
}
return (
<React.Fragment>
<Button
// component="button"
color="primary"
onClick={handleClickOpen}
style={{ float: "right"}}
variant="outlined"
>
Create
</Button>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="form-dialog-title"
>
{!isSubmitionCompleted &&
<React.Fragment>
<DialogContent>
<Formik
initialValues={{ title: "", category: [], subcategory: "" }}
onSubmit={(values, { setSubmitting }) => {
setSubmitting(true);
firestore.collection("study").doc().set({
...values,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
})
.then(() => {
setSubmitionCompleted(true);
});
}}
validationSchema={Yup.object().shape({
title: Yup.string()
.required('Required'),
category: Yup.string()
.required('Required'),
})}
>
{(props) => {
const {
values,
touched,
errors,
dirty,
isSubmitting,
handleChange,
handleBlur,
handleSubmit,
handleReset,
} = props;
return (
<form onSubmit={handleSubmit}>
<TextField
label="Title"
name="title"
// className={classes.textField}
value={values.title}
onChange={handleChange}
onBlur={handleBlur}
helperText={(errors.title && touched.title) && errors.title}
margin="normal"
style={{ width: "100%"}}
/>
<Box margin={1}>
<Field
name="category"
multiple
component={Autocomplete}
options={allCategories}
// value={values.label}
// value={values.value}
// value={allCategories.value}
// value={values.category.allCategories.value}
我尝试了这些尝试中的每一个(一次一个),以使数组仅填充一个字段 - 但它们都没有做到这一点。相反,firebase 在其数组中记录标签和值。
getOptionLabel={(option: any) => option.label}
style={{width: '100%'}}
renderInput={(params: AutocompleteRenderInputParams) => (
<MuiTextField
{...params}
error={touched['autocomplete'] && !!errors['autocomplete']}
helperText={touched['autocomplete'] && errors['autocomplete']}
label="Category"
variant="outlined"
/>
)}
/>
</Box>
<TextField
label="Subcategory "
name="subcategory"
// className={classes.textField}
value={values.subcategory}
onChange={handleChange}
onBlur={handleBlur}
helperText={(errors.subcategory && touched.subcategory) && errors.subcategory}
margin="normal"
style={{ width: "100%"}}
/>
<DialogActions>
<Button
type="button"
className="outline"
onClick={handleReset}
disabled={!dirty || isSubmitting}
>
Reset
</Button>
<Button type="submit" disabled={isSubmitting}>
Submit
</Button>
{/* <DisplayFormikState {...props} /> */}
</DialogActions>
</form>
);
}}
</Formik>
</DialogContent>
</React.Fragment>
}
{isSubmitionCompleted &&
<React.Fragment>
<DialogTitle id="form-dialog-title">Done!</DialogTitle>
<DialogContent>
<DialogActions>
<Button
type="button"
className="outline"
onClick={handleClose}
>
Close
</Button>
{/* <DisplayFormikState {...props} /> */}
</DialogActions>
</DialogContent>
</React.Fragment>}
</Dialog>
</React.Fragment>
);
}
export default Summary;
然后,当我尝试查询 firebase 时,我试图查找类别包括健康的文档。
我已经尝试了下面的每个 where 查询,但我无法让它们中的任何一个返回查询结果(如果我删除 where 查询,我可以返回所有结果):
function useHealthTerms() {
const [healthTerms, setHealthTerms] = useState([])
useEffect(() => {
firebase
.firestore()
.collection("study")
//.where("title", "==", "ss")
注意 - 这可以找到标题。标题字段与类别字段处于同一级别
//.where('category', '==', 'health')
//.where('category.value', "array-contains", 'health")
//.where('category', 'array-contains', 'health')
//.where('category', 'array-contains', 1)
//.where("category.1.value", '==', 'health')
.onSnapshot(snapshot => {
const healthTerms = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data(),
}))
setHealthTerms(healthTerms)
})
}, [])
return healthTerms
}
我看过这篇文章,但我不够聪明,无法从答案中理解。
我也看过这篇文章和贝蒂建议的答案。我已经尝试了以下查询构造的多种变体来尝试使用这个想法,但每次我都会收到查询形式的错误。
.where(new firebase.firestore().FieldPath("category", "value"), '==', 'health')
我想知道是否可以尝试在 formik 中获取类别表单字段只是为了保存 option.value 而不是标签和值。
我看不到 formik handleChange 如何要求它只保存值。
即使那样,我也看不到如何查询 firestore 以使用数组的内容作为查询参数。
有人知道吗:
如何通过formik表单提交到firestore在自动完成中仅保存选项值(而不是选项标签和值)?
如何在firestore中查询数组的内容以查看其属性之一是否与查询匹配?
这很奇怪,因为这篇文章表明应该可以使用我在上面尝试过的表单对数组进行 where 查询。但是,这篇文章建议使用以下格式 .collection(study/[docId]).where("value", "==", "health")。我需要它来搜索集合中的每个文档,所以我不知道如何将这种方法应用于这个问题。
下面来自 gso_gabriel 的答案暗示了两件令人困惑的事情。首先,假设我使用了子集合。我没有。添加下图以显示类别字段在父文档中。我可以使用上面显示的格式对标题进行 where 查询以提取值。
其次,也是最令人困惑的一点 - 它说:“因为您无法在数组中搜索对象”。这是什么意思?是不是提示不能对category字段内的value内容进行查询?如果是这种情况,是否有资源提供有关如何查询该数据的指导?
我也看过这篇文章- 答案表明使用 firebase 无法查询类别中的值。问题是我无法理解建议的替代方法。如果我正确理解了这篇文章,是否有任何教程扩展了这些原则,以便我可以尝试找到不同的查询策略?
这篇文章的第一个答案也表明不可能在类别内查询值。第二个答案建议在 where 查询中使用不同的格式 - 如下所示。
.where("category", "array-contains", {value: "health", label: "Health & Medical"})
答案强调了将整个数组内容添加到花括号中的重要性。这行得通。
所以 - 这让我回到了自动完成提交处理程序。这是一个多选字段,因此可能选择了多个值。如何在 firebase 文档中将它们变成一组单一值。即使只有一个,我如何更改提交处理程序以便它只发送选择选项值而不是值和标签?
如果无法查询数组中的对象 - 如何更改提交处理程序以仅将选定的选项值添加到 firebase,而不是同时添加标签和值?在这篇文章的第一个答案中建议的解决方法是添加一个仅保存要查询的值的字段(例如:health)。
解决方案
在提交到 firebase 之前,onSubmit
您可以更改您发送的数据的形状
onSubmit={(values, { setSubmitting }) => {
setSubmitting(true);
firestore.collection("study").doc().set({
...values,
category: values.category.map(c => c.value),
createdAt: firebase.firestore.FieldValue.serverTimestamp()
})
.then(() => {
setSubmitionCompleted(true);
});
}}
推荐阅读
- python - 具有不同集合的自定义嵌套 json 结构
- python-3.x - 无法从 keras 中的模块导入方法
- javascript - TinyMCE 5:向工具栏按钮添加自定义属性
- leaflet - 传单地图完全灰色以编程方式打开弹出式 tofa 标记
- go - 有没有办法在 Cloud Firestore 的(Go)代码中创建索引豁免?
- ruby-on-rails - 如何从 request.env 获取登录信息?
- hadoop - 为什么我的猪查询返回错误的值
- node.js - 文件上传到 Amazon s3 时访问被拒绝
- c - 为什么我无法访问包含的功能?
- google-cloud-dataflow - 由于未找到 ext4,数据流(Beam 2.12)无法启动