在mongodb实现中嵌套文档,就像Reddit注释

时间:2018-12-31 19:58:36

标签: node.js mongodb mongoose

在我的项目中,我想实现一个由评论列表组成的评论部分。

const myschema= mongoose.Schema({
    _id: mongoose.Schema.Types.ObjectId,
    //other fields
    comments : [comment]
 },{collection : 'TABLE_NAME'} );


const comment= mongoose.Schema({
    _id : mongoose.Schema.Types.ObjectId,

    commentid: String, // id consists of uuid1()
    senderid: Number, //user's id
    body: String, // useful information
    parent: String,// parent id consists of uuid1()
    children: [] // I couldn't add children = [comment], it gives me an error, 
    //instead, I make it empty and will fill it when a comment comes
})

在请求标签中,我将收到以下格式的JSON:

{
 "userid": "NUMBERID HERE",
 "comment": "COMMENT BODY",
 "parent" : "Comment's parent id"
}

我想添加一条评论,它可以是另一条评论的子项。如何搜索并找到合适的位置?

如果JSON主体中没有父级,我正在这样做:

// import comment somewhere at the beginning
.then(doc =>{

var newc= new comment();
newc.cid = uuidv1();
newc.sender = req.body.userid;
newc.body = req.body.comment;
newc.parent = "";
newc.children = "";
doc.comments.push(newc);

// save to DB
doc
.save()
.then(docres =>{
     res.status(200).json(docres);
})
.catch(err => {
     res.status(500).json({error: err});
})
}

我不知道如何找到深入的评论

2 个答案:

答案 0 :(得分:0)

不能给定未指定的,任意嵌套的深度的数组元素或对象属性。只是不可能。您将需要在应用程序层中进行处理。对数据进行非规范化在很多情况下都可以,但是建议不要将任意嵌套深度用于数据非规范化,尤其是因为您无法有效地建立索引!

如果您想要一个纯MongoDB解决方案,那么您将需要一个不同的文档结构。我建议您看一下documentation,尤其是有关array of ancestors的部分,以便正确地对数据建模。

答案 1 :(得分:0)

我找到了解决方法。

手动遍历注释并在正确的位置插入即可。但是,它只能在一定程度上起作用。就我而言,我可以在评论下方插入评论并保存。我还可以插入第3个深度注释,并查看我插入的对象的JSON转储,甚至将其包装在HTTP响应对象中并发送给客户端。但是数据库不会保存此更新。

我要做的是,在正确的位置插入注释之后,我在保存到数据库之前添加了此代码。

  doc.markModified('comments'); // this is added
  doc.save().then(/*prepare response*/);

以某种方式,MongoDB或mongoose或javascript解释器知道文档已更改并保存更新的版本。如果未指定markmodified部分,则编译器可能认为该对象尚未修改,因此跳过该对象。

希望这对遇到此问题的人有所帮助。 这是我的实现

        // find the document which comment is going to be inserted
        MyDOC.findOne({'id' : req.params.id})
        .exec()
        .then(doc =>{
            // if the comment has a parent, it should be inserted in nested
            if(req.body.parent != null && req.body.parent != undefined)
            {
                // find correct position and insert
                findComment(doc.comments, req.body);
                doc.markModified('comments');
                doc
                .save()
                .then(docres =>{
                    res.status(200).json(docres);
                })
                .catch(err => {
                    console.log(err);
                    res.status(500).json({error: err});
                })
            }
            else
            {
                //Add comment to the root level
                var comment= new Comment();
                comment.cid = uuidv1();
                comment.body = req.body.comment;
                comment.parent = "";

                doc.comments.push(comment);
                doc.markModified('comments');
                // save to DB
                doc
                .save()
                .then(docres =>{
                    res.status(200).json(docres);
                })
                .catch(err => {
                    console.log(err);
                    res.status(500).json({error: err});
                })
                }
        })


function findComment(comment, body)
{
    comment.forEach(element => {
        if(element.children.length != 0)
        {
            if(element.cid === body.parent)
            {
                // found, insert
                var comment= new Comment();

                comment.cid = uuidv1();
                comment.body = body.comment;
                comment.parent = body.parent;

                element.children.push(comment);
                return true;
            }

            if(findComment(element.children, body, usr))
                return true;
        }
        else
        {
            // this comment does not have children. If this comments id and the body's parent is equal, add it
            if(element.cid === body.parent)
            {
                // found, insert
                var comment= new Comment();

                comment.cid = uuidv1();
                comment.body = body.comment;
                comment.parent = body.parent;

                element.children.push(comment);
                return true;
            }
            return false;
        }
    });
}