Javascript 使用Mongodb响应本机聊天

Javascript 使用Mongodb响应本机聊天,javascript,mongodb,asynchronous,react-native,chat,Javascript,Mongodb,Asynchronous,React Native,Chat,我对react native非常陌生,目前正在开发聊天/论坛应用程序。最近,我在尝试为我的应用程序创建直接消息部分时遇到了一些问题。我不知道如何将我的数据库连接到前端。问题是: 我使用一个mongodb数据库,它由两个集合组成:消息和对话 每个会话都有一个唯一的Id,每条消息都有一个对应于它所属的会话的chatId 在我的react原生应用程序中,在一个直接消息组件中,我有一个显示不同聊天记录的flatlist 当直接消息组件willMount()调用异步函数getChats(),该函数从当前用

我对react native非常陌生,目前正在开发聊天/论坛应用程序。最近,我在尝试为我的应用程序创建直接消息部分时遇到了一些问题。我不知道如何将我的数据库连接到前端。问题是:

我使用一个mongodb数据库,它由两个集合组成:消息和对话

每个会话都有一个唯一的Id,每条消息都有一个对应于它所属的会话的chatId

在我的react原生应用程序中,在一个直接消息组件中,我有一个显示不同聊天记录的
flatlist

当直接消息组件
willMount()
调用异步函数
getChats()
,该函数从当前用户所属的数据库中获取聊天记录。然后将获取的聊天设置为状态

然后,在
getChats()
中,在聊天设置为状态后,我有一个
for循环
,它基本上循环了整个
this.state.chats
数组,然后调用一个函数
getMessages(this.state.chats[I].id)
,该函数获取与聊天id共享相同聊天id的所有消息。然后将获取的消息添加到
this.state.messages

最后,一个带有道具的
平面列表

keyExtractor={(item)=>item.\u id}
数据={this.state.chats}
renderItem={({item})=>此
extraData={this.state}

,呈现聊天记录

我希望能够在聊天
视图中显示最新的消息内容和发件人,但是,有一个错误指出消息内容未定义

我认为这可能是因为消息没有设置为聊天前的状态,但我不确定

你将如何解决这个问题?您要更改前端还是后端?你能把两者都换一下吗?我应该分享我的代码以便更容易理解问题吗


提前谢谢。

对问题的解释非常清楚!简言之:

如何使用React Native、MongoDB、NodeJS和Express构建包含对话概述(显示每个对话的最后一条消息)的聊天页面

一些注意事项:

  • 使用一致的命名,即将
    chatId
    重命名为
    conversationId
    ,将
    chats
    重命名为
    conversations
  • 尽量减少互联网请求,因为它们是资源密集型的,而且速度很慢

    • 现在,您的算法进行
      对话。每次打开页面时,count+1
      请求可能只是
      1
    • 对于第一页,您只需要每次对话中的最后一条消息
    • 打开对话页面时,加载对话的其余消息
    • 因此,您不需要
      extraData
      字段
    • (尽管存在缓存,请参见其他注释)
    • 例如,使用GraphQL
      query('currentUser.conversations{text,messages(limit 1),…}')
    • 例如,使用rest+mongoose:

      // controller
      // see https://stackoverflow.com/questions/32207457/node-js-mongoose-populate-limit
      // populate the first item in conversation.messages
      const conversations = ()=> db.Conversations
        .find(...)
        .populate({ path: 'messages', options: { limit: 1, sort: { created: -1} }}))
        .exec(...)
      
      // router
      router.get('/conversations', ({user}, res)=>
        getConversations({user})
          .then(data=> res.send({data}))
          .catch(error=> res.send({error}))
      )
      
    • (这假设消息是会话中的虚拟财产)

  • 假设所有数据都已损坏;如果消息数据丢失,应用程序不应该崩溃。在访问属性之前,请检查该属性是否存在,并在继续之前将其转换为预期的数据类型

    • 确保错误没有被“吞没”;例如,确保始终有一个
      。如果有
      ,请捕获
      ,并记录错误。然后
      ,并将错误消息粘贴到问题上(如果有)
    • Uncaught TypeError:在执行
      a.b.c
      时,如果您知道
      a
      是一个对象,则无法读取未定义的属性“c”,可以通过首先检查来避免<代码>如果(a.b)使用(a.b.c)
      ,或使用短路:
      a.b&&use(a.b.c)
  • 正确的假设,发生了什么:
    • ConversationsPage
      已初始化,
      状态。conversations
      为空
    • willMount
      调用->
      fetchAllConversations
      已启动,需要时间,异步
    • willMount
      ends->
      render
      called->empty list rendered
    • fetchAllConversations
      '第一个请求完成->
      setState{conversations}
      ->
      render
      再次调用->呈现完整列表(在您的情况下,它崩溃是因为缺少最后一个消息字段)
    • fetchAllConversations
      调用
      fetchMessagesForConversations
      ,这会发出许多api请求,并可能多次调用
      setState
      ,从而导致重新呈现
  • 不要忘记加载状态

      state = {loading: false}
      render () {
        const {loading} = this.state
        return <FlatList renderHeader={()=> loading? <ActivityIndicator .../>: null} .../>
      }
    
  • 这将使流量减少到:

    • ConversationsPage
      已初始化,
      状态。conversations
      为空
    • willMount
      调用->
      reload
      已启动,需要时间,异步
    • willMount
      ends->
      render
      called->loading indicator rendered
    • 重新加载
      的唯一请求完成->
      设置状态{conversations}
      ->
      再次调用渲染
      ->渲染的完整列表

补充说明:

  • 查看
    docker
    以简化服务器设置(即让mongodb+NodeJ一起运行)
  • 我假设您已经有了一个中间件来进行身份验证,并在查询中添加了正确的授权逻辑(例如,仅查找授权用户应有权访问的对话/消息)
    • ie.
      db.Conversation.find({参与者:{$includes:req.user.\u id}})//伪代码
    • 例如,在消息中,首先查看具有该id的对话是否有用户作为参与者
  • 如何处理分页?(例如,为了防止数据传输速度慢
      state = {loading: false}
      render () {
        const {loading} = this.state
        return <FlatList renderHeader={()=> loading? <ActivityIndicator .../>: null} .../>
      }
    
    async fetchAllConversations () {
      const conversations = await api.conversations()
      await Promise.all(conversations.map(c=> c.messages = await api.messagesForConversationId(c._id)))
      // similar to for (let i=0; i<conversations.length; i++) {
      //  const c = conversations[i]; c.messages = await api.messagesForConversationId(c._id)}
      return conversations
    }
    async reload () {
      this.setState({loading: true})
      this.fetchAllConversations()
        .then(conversations=> this.setState({conversations}))
        .catch(showError)
        // stop loading both on error and success
        .then(()=> this.setState({loading: false}))
    }
    state = {loading: false, conversations: []}
    willMount () { this.reload() }
    
    async fetchAllConversationsIncludingLastMessage () {
      const conversations = await api.conversationsWithLastMessage()
      return conversations
    }