使用 socket.io 将新的数组更改应用于 useEffect 并更改流

Apply new array changes to useEffect with socket.io and change streams

我目前正在构建一个社交平台,我利用 Mongo Change Streams 来检测任何更改,其中更改将“发出”到单独的套接字,这是我之前遇到的问题是,一切都运行良好,但现在由于嵌套评论和回复的实施,我的数据库结构发生了变化。因此,我想出了一个解决方法,将三个单独的数组合并为一个数组,其中嵌套数组信息与喜欢和评论相关联。所以我想要的是我想从单独的套接字(帖子、喜欢、评论)中获取数据并合并到一个套接字中,因此我已经应用了一个处理程序来检查新旧数据,所以基本上我只是坚持将这三个套接字数据合并到一个数组中,我有点不知道如何采用这种方法。

改变流

const db = mongoose.connection;
db.once('open', () => {
    //post changes
    console.log(chalk.blueBright("Setting change streams"));
    db.collection('posts').watch()
    .on('change', change => {
        if(change.operationType === 'insert'){
            console.log(chalk.yellowBright('INSERTED'))
            io.emit('posts', change.fullDocument);
            console.log(change.fullDocument)
        }
    });
    db.collection('posts').watch({ fullDocument: 'updateLookup' })
    .on('change', change => {
        if(change.operationType === 'update'){
            console.log(chalk.yellowBright('UPDATED'));
            io.emit('posts', change.fullDocument);
            console.log(change.fullDocument)
        }
    })

    //comments changes
    db.collection('comments').watch({ fullDocument: 'updateLookup' })
    .on('change', change => {
        if(change.operationType === 'insert'){
            console.log(chalk.yellowBright('INSERTED'))
            io.emit('comments', change.fullDocument);
            console.log(change.fullDocument)
        }
    });
    db.collection('comments').watch({ fullDocument: 'updateLookup' })
    .on('change', change => {
        if(change.operationType === 'update'){
            console.log(chalk.yellowBright('UPDATED'));
            io.emit('comments', change.fullDocument);
            console.log(change.fullDocument)
        }
    })
}); 

客户端

useEffect 检测帖子的任何变化

//Check socket changes
    useEffect(() => {
      //merged posts with comments and likes sockets?
      //this is the solution I've come up on merging three arrays but
      //I'd like to apply this with the three sockets data that are being retrieved or applied
      const newPosts = posts.map(post => ({
        ...post,
        likes: likes.filter(like => post.likes.map(like => like._id).includes(like._id)),
        comments: comments.filter(comment => post.comments.map(comment => comment._id).includes(comment._id)),
      }))

      const handler = (item) => {
        setPosts((oldPosts) => {
          const findItem = oldPosts.find((post) => post._id === item._id);
          if (findItem) {
            return oldPosts.map((post) => (post._id === item._id ? item : post));
          } else {
            return [item, ...oldPosts];
          }
        });   
      };

      //Sockets
      //socket.off("comments", handler);
      //socket.off("likes", handler);

      return () => socket.off("posts", handler);
       //eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

对此有两种解决方案,第一种是将调用套接字的方式更改为 socket.onMany(handler),它会添加一个侦听器,该侦听器将在发出任何事件时触发。在那里,输出将存储为 [["posts",{}],["comment",{}],["likes"],{}],接下来要做的是使用“.splice(indexOf('posts'))”删除字符串值,然后您需要展平将三个数组转化为对象,并通过关联的id将它们相互合并:

const newPosts = posts.map(post => ({
    ...post,
    likes: likes.filter(like => post.likes.map(like => like.id).includes(like.id)),
    comments: comments.filter(comment => post.comments.map(comment => comment.id).includes(comment.id)),
}))

第二种方法是修改更改流,调用 Post 模型并使用 populate(),它每次都会使用填充的数据调用对数据库的新请求需要然后将其发送到您的套接字,因此由于帖子将是父文档,因此只应在帖子套接字中检查更改。

//post changes
    console.log(chalk.blueBright("Setting change streams"));
    db.collection('posts').watch()
    .on('change', change => {
        if(change.operationType === 'insert'){
            PostModel.find({}).lean().populate('comments')
            .then((posts) => io.emit('posts', posts))
        }
    })
    db.collection('posts').watch({ fullDocument: 'updateLookup' })
    .on('change', change => {
        if(change.operationType === 'update'){
            PostModel.find({}).lean().populate('comments')
            .then((posts) => io.emit('posts', posts))
        }
    })