【问题标题】:Complex search query in firebasefirebase 中的复杂搜索查询
【发布时间】:2021-07-13 08:50:03
【问题描述】:

我是 React Native 和 Firebase 的新手,我正在使用 firestore 构建应用程序。

firestore db 的结构如下所示:

AllPosts > Doc(每个帖子) > Field(name,desc, .... , userId="12345")

对于用户

users > doc(每个用户) id 12345 > field(name,desc,etc)

我不知道这是否是设置数据库的最佳方式。但是当我进入帖子屏幕时,我需要加载该帖子的所有数据以及创建帖子的 userId 的数据,但它们位于完全不同的集合中。

我找不到这样做的好方法。 我已经尝试将 userId 字段从 post doc 设置为 const 'fetchUserById' 并基于此执行查询,但我认为这是完全错误的

    const [post, setPost] = useState([]);
    const [user, setUser] = useState(null);

        useEffect(() => {
    
            firebase.firestore()
            .collection("allPosts")
            .where(firebase.firestore.FieldPath.documentId(), '==', props.route.params.postId)
            .get()
            .then((snapshot) => {
                let data = snapshot.docs.map(doc => {
                    const data = doc.data();
                    const id = doc.id;
                    return { id, ...data }
                })
                setPost(data)
            })

            const fetchUserById = post.userId;

            firebase.firestore()
            .collection('users')
            .where(fetchUserById, '==', firebase.firestore.FieldPath.documentId())
            .get()
            .then((snapshot) => {
                if (snapshot.exists) {
                    setUser(snapshot.data());
                }
                else {
                    
                }
            })
           
            
    
        },[])

【问题讨论】:

    标签: reactjs firebase react-native google-cloud-firestore


    【解决方案1】:

    如果您知道文档 ID,则不应使用 where 方法。

    firebase.firestore().collection('users')
        .doc(props.route.params.postId)
        .get()
        .then((snapshot) => {
            if (snapshot.exists) {
                setUser(snapshot.data());
            } else {
                        
            }
        })
    

    get() 方法返回一个DocumentSnapshot。

    第二个查询也是如此,只是需要注意,.where() 中的第一个参数是您要查找的字段名称或路径,第三个参数是值。

    @param fieldPath — The path to compare
    
    @param opStr — The operation string (e.g "<", "<=", "==", ">", ">=").
    
    @param value — The value for comparison
    

    【讨论】:

    • 我认为行不通。正如我上面所说,我有 2 个单独的集合,用户和 Allposts。在 allPosts 中,我有包含各种字段的文档,包括创建者用户的字段“userId”。我的目标是从该字段中获取 userId 值,并在 firestore 中找到一个文档,名称 == 到 allPosts 集合中的 userId 路径
    【解决方案2】:

    由于您将文档 ID 存储在 post.userId 中,因此您可以像这样直接按 ID 选择文档:

     firebase.firestore()
                .collection('users')
                .doc(post.userId)
                .get()
                .then((snapshot) => {
                    if (snapshot.exists) {
                        setUser(snapshot.data());
                    }
                    else {
                        
                    }
                })
    

    您获得undefined is not an object 的原因是因为post 尚未在useEffect 的执行中设置。流程如下:

    1. 组件渲染方法被调用
    2. post 设置为默认值[](您似乎不希望有一组帖子,所以它可能不应该是 [])
    3. useEffect() 回调被调用
    4. 您从 firestore 获取 allPosts
    5. 你打电话给setPost(data)
      • 这会触发状态更新并重新渲染组件
    6. 在重新渲染的组件中,post 变量现在设置为帖子集合,但在仍在运行的 useEffect() 回调中,post 变量仍然相同(空数组)。
    7. 获取用户失败,因为 post.userId 未定义

    你有多种解决方法:

    1. 您可以将post.userId 存储在useEffect() 回调内的局部变量中
    2. 你可以有一个单独的useEffect 依赖于帖子。

    我更喜欢第一种方法,当您需要单个文档的 id 时,也不应该使用where 条件。总的来说,你的代码应该是这样的(我想,现在没有地方可以测试它):

    const [post, setPost] = useState(null); // you don't need an array here. You get 1 post and 1 user for it.
    const [user, setUser] = useState(null);
    
        useEffect(() => {
            firebase.firestore()
            .collection("allPosts")
            .doc(props.route.params.postId) // no need to use `where`
            .get()
            .then((snapshot) => {
                const postData =snapshot.data();
                setPost(postData) // getting single document, no need to iterate over results
                // you cannot fetch user before you know its id so your next query should be inside of `then` callback 
                firebase.firestore()
                        .collection('users')
                        .doc(postData.userId)
                        .get()
                        .then((snapshot) => {
                            if (snapshot.exists) {
                                setUser(snapshot.data());
                            }
                        })
            })
        },[props.route.params.postId]) // you probably want to re-fetch if postId changes
    

    【讨论】:

    • 这听起来像是一个很好的解决方案,但它只是不断抛出错误“未定义不是对象”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    相关资源
    最近更新 更多