【问题标题】:How to save multiples refs into one document in MongoDB with mongoose?如何使用 mongoose 将多个 refs 保存到 MongoDB 中的一个文档中?
【发布时间】:2020-10-19 18:55:23
【问题描述】:

我正在尝试将多个标签保存到我刚刚创建的特定产品中。我成功地将标签推送到产品集合中,但是当我尝试保存它时出现错误:无法同时保存()同一个文档多次。

我正在使用 mongoDB、node 和 Mongoose。

这是我的架构


var tagSchema = mongoose.Schema({
    tagname: String,
});

var tag = mongoose.model('Tag', tagSchema);


var Item = new Schema({
    title : String,
    description : String,
    price : Number,
    tags:  [{
        type: mongoose.Schema.Types.ObjectId,
        ref: "Tag"
    }]
});

var product = mongoose.model('Product', Item);

当我尝试在数据库中创建具有关联标签的新产品时,我在 node.js 中的代码(来自 HTML 表单)


product.create(req.body.product, function(err, newitem){
            if(err){
                console.log(err);
            }else{

             console.log(req.body.tags); // gives ["fun","cheap"] from the form
             req.body.tags.forEach(function(newtag){
             tag.findOne({tagname : newtag},function(err, finalcast){


             newitem.tags.push(finalcast); 
             console.log(newitem); // gives the product with the tag collections in it.

               });
              newitem.save(); // error Can't save() the same doc multiple times in parallel.
              console.log(newitem); // the product collection has an empty tags[] 

               });


                 res.redirect("/");

            }

        });


如何一次将标签集合直接保存在产品中?创建产品然后使用 push 将标签一一插入是否更好?

非常感谢您的帮助!

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    问题可能是因为你试图通过这样做来推送对象而不是 _id

    newitem.tags.push(finalcast);
    

    尝试像这样推送对象的_id:

    newitem.tags.push(finalcast._id);
    

    【讨论】:

      【解决方案2】:

      我认为这与 Asynchrone JS 有关,但我不确定。那里的循环似乎不是一个好主意...

      如何轻松将多个标签文档保存到一个产品文档中?

      【讨论】:

        【解决方案3】:

        好吧,经过几个小时的工作,我找到了解决方案。我真的不知道这是否是一个好方法,但它确实有效。我在 forEach 中插入一个 if() 以仅在 forEach 循环完成时保存:

         req.body.tags.forEach(function(newtag, index){
                            tag.findOne({tagname : newtag},function(err, finalcast){
        
                            newitem.tags.push(finalcast); 
        
                            if(index + 1 == req.body.tags.length){
                            newitem.save();
                            res.redirect("/");
        
                            }
                       });
        

        【讨论】:

          【解决方案4】:

          您在forEach 循环中一次执行所有这些操作,这使得很难知道数据库操作何时完成。这也意味着您在操作实际完成之前触发了res.redirect。我会为此使用异步/等待。我写得很快,还没有测试过,但我认为它应该可以工作:

          const tagSchema = mongoose.Schema({
            tagname: String
          })
          
          const Tag = mongoose.model('Tag', tagSchema)
          
          const itemSchema = new Schema({
            title: String,
            description: String,
            price: Number,
            tags: [{
              type: mongoose.Schema.Types.ObjectId,
              ref: "Tag"
            }]
          })
          
          const Product = mongoose.model('Product', itemSchema)
          
          
          const createProduct = async (req, res) => {
            const { tags, product } = req.body
          
            try {
              const product = new Product(product)
          
              for (let i = 0; i < tags.length; i++) {
                const tagName = tags[i]
                const existingTag = await Tag.findOne({ tagname: tagName })
          
                if (!existingTag) {
                  await new Tag({ tagname: tagName}).save()
                }
              }
          
              await product.save()
          
              res.redirect('/') 
          
            } catch (error) {
              console.log(error)
            }
          }
          

          在代码中我做了几件事:

          • 使用 async/await 以便一次执行一件事,而不是同步执行。
          • 清理了代码:缩进等有点乱(我使用的是 StandardJS 样式)
          • 模型使用帕斯卡大小写,因为它们是对象构造函数。模型以大写字母开头是有原因的。
          • 使用 for 循环而不是 forEach,因为 forEach 不适用于异步。

          【讨论】:

          • 非常感谢!了解它的工作原理对我有很大帮助。
          • 很高兴能帮上忙!如果您对答案感到满意,请不要忘记投票/标记为正确答案。
          猜你喜欢
          • 1970-01-01
          • 2018-09-20
          • 1970-01-01
          • 2012-05-03
          • 2015-07-18
          • 2017-09-22
          • 2019-03-10
          • 1970-01-01
          • 2015-08-21
          相关资源
          最近更新 更多