猫鼬模式参考与嵌入数组

Posted

技术标签:

【中文标题】猫鼬模式参考与嵌入数组【英文标题】:mongoose schema reference vs embed array 【发布时间】:2018-06-20 15:51:43 【问题描述】:

我有一个包含 express 和 mongoose 的应用程序。我有两个模式,一个博客模式和一个评论模式。我想使用 RESTful 路由将评论数组从表单推送到单个博客。如果我在博客模式中嵌入评论模式它可以工作,另一方面,如果我在博客模式中引用评论模式的 ObjectId,则代码适用于第一条评论,然后在第二条评论中,控制台抛出验证错误:

(node:5472) UnhandledPromiseRejectionWarning: 
Unhandled promise rejection (rejection id: 1): 
ValidationError: Blog validation failed: 
comments: Cast to [undefined] failed for value 
"[
  "_id":"5a57374da3ba43156005c881",
  "text":"test1",
  "author":"test1",
  "__v":0
]" 
at path "comments"

记录的对象是我推送到数组的第一条评论

这是博客架构(嵌入版)

//Embed

var mongoose = require("mongoose");

var comment = new mongoose.Schema(
    text: String,
    author: String
);

var blogSchema = new mongoose.Schema(
    name: String,
    image: String,
    description: String,
    comments: [comment]
);

module.exports = mongoose.model("Blog", blogSchema);

这是博客架构(参考版)

// Reference

var mongoose = require("mongoose");

var blogSchema = new mongoose.Schema(
    name: String,
    image: String,
    description: String,
    comments: [
        type: mongoose.Schema.Types.ObjectId,
        ref: "Comment"
    ]
);

module.exports = mongoose.model("Blog", blogSchema);

这是评论模式

var mongoose = require("mongoose");

var commentSchema = new mongoose.Schema(
    text: String,
    author: String
);

module.exports = mongoose.model("Comment", commentSchema);

这是我用来发表新评论的评论路线

app.post("/blogs/:id/comments", function (req, res) 
    // find the correct campground
    Blog.findById(req.params.id, function (err, blog) 
        if (err) 
            console.log(err);
            res.redirect("/blogs");
         else 
            Comment.create(req.body.comment, function (err, comment) 
                if (err) 
                    console.log(err);
                 else 
                    blog.comments.push(comment);
                    blog.save();
                    res.redirect("/blogs/" + blog._id);
                
            );
        
    );
);

请注意,路由正常工作并重定向到“blogs/:id”页面,如果我 console.log 博客或 che 评论对象我有正确的输出

最后,这是我用来发布请求的表单:

<div class="container">
    <div class="row">
        <h1 style="text-align: center;">Add a new Comment to <%= blog.name %></h1>
        <div style="width: 30%; margin:25px auto;">
            <form action="/blog/<%= blog._id %>/comments" method="POST">
                <div class="form-group">
                    <input class="form-control" type="text" name="comment[text]" placeholder="text">
                </div>
                <div class="form-group">
                    <input class="form-control"  type="text" name="comment[author]" placeholder="author">
                </div>
                <div class="form-group">
                    <button class="btn btn-lg btn-primary btn-block">Submit!</button>
                </div>
            </form>
            <a href="/blogs">Go Back</a>
        </div>
    </div>
</div>

编辑我宁愿只使用评论的 ID 而不是完整的评论模式,但我不知道如何设置应用程序来做到这一点。

mongoose github profile 也报同样的错误:https://github.com/Automattic/mongoose/issues/5972

【问题讨论】:

【参考方案1】:

我发现解决此问题的唯一方法是将我的代码重构为如下所示:

app.post("/blogs/:id/comments", function (req, res) 
    Comment.create(req.body.comment, function (err, comment) 
        if (err) 
            console.log(err);
         else 
            Blog.findOne("_id": req.params.id)
            .populate("comments")
            .exec(function (err, blog) 
                if (err) 
                    console.log(err);
                    res.redirect("/blogs");
                 else 
                    blog.comments.push(comment);
                    blog.save();
                    res.redirect("/blogs/" + blog._id);
                
            );
        
    );
);

但这并不能解释模式的行为

希望对你有帮助

【讨论】:

【参考方案2】:

参考版:创建评论后,您可以简单地将创建的评论文档的id推送到博客文档中。

blog.comments.push(comment._id); 

blog.comments.push(mongoose.Types.ObjectId(comment._id)); //to ensure the pushed id will be mongoose object id.

第 2 步必须要求 mongoose。

【讨论】:

谢谢,我试过你的代码,但不起作用:控制台记录了同样的错误 .create() 方法返回一个对象数组,这可能是它给出错误的情况。通过在控制台中打印comment 来检查这一点。如果它给你数组而不是使用数组索引来获取保存的评论文档。或者使用let comment = new Comment(req.body.comment);comment.save 方法而不是Comment.create()。 .save() 返回一个保存的猫鼬对象 谢谢,我尝试了一些变通方法,终于找到了解决方案(见下面的答案)

以上是关于猫鼬模式参考与嵌入数组的主要内容,如果未能解决你的问题,请参考以下文章

猫鼬设计模型中的嵌入式文档与参考?

猫鼬设计模型中的嵌入式文档与参考?

构建我的猫鼬模式的最佳方式:嵌入式数组、填充、子文档?

具有角色的参考数组的猫鼬模式

在猫鼬中仅更改整个嵌入式文档数组的一个字段

在猫鼬中仅更改整个嵌入式文档数组的一个字段