【问题标题】:Update database with multiple reference database issues使用多个参考数据库问题更新数据库
【发布时间】:2017-05-04 21:33:31
【问题描述】:

我对猫鼬/快递很陌生。我正在努力尝试从 html 表单更新新数据并将其保存到具有引用的数据库中。我有一个位置参考位置模型的商业模型。这是代码。

edit.ejs

<div class="container">
    <div class="form-container">
        <form action="/<%= bus._id %>?_method=PUT" method="POST">
            <!-- business info -->
            <h3>Business Information</h3>
            <input class="form-input" type="input" name="bus[logo]" value="<%= bus.logo %>">
            <input class="form-input" type="input" name="bus[name]" value="<%= bus.name %>">
            <% bus.location.forEach(function(location) { %>
            <input class="form-input" type="input" name="bus.location[street]" value="<%= location.street %>">
            <input class="form-input" type="input" name="bus.location[city]" value="<%= location.city %>">
            <div class="state-input">
                <select class="form-inline" name="bus.location[state]">
                    <option value="" disabled selected><%= location.state %></option>
                    <option value="AL">Alabama</option>
                    ...
                    <option value="WY">Wyoming</option>
                </select>   
            </div><!--State-input -->
            <input class="form-inline" type="input" name="bus.location[zipcode]" value="<%= location.zipcode %>">
            <% }) %>
            <!--Contact info-->
            <h4>Contact Information</h4>
            <% bus.contact.forEach(function(contact) { %>
            <input class="form-input" type="url" name="bus[url]" value="<%= bus.url %>">
            <input class="form-input" type="email" name="bus.contact[email]" value="<%= contact.email %>">
            <input class="form-input" type="tel" name="bus.contact[phone]" value="<%= contact.phone %>">
            <input class="form-input" type="input" name="bus.contact[twitter]" value= "<%= contact.twitter %>">
            <input class="form-input" type="input" name="bus.contact[facebook]" value="<%= contact.facebook %>">
            <input class="form-input" type="input" name="bus.contact[instagram]" value="<%= contact.instagram %>">
            <% }) %>

index.js - 编辑路线

//(edit.ejs) Edit Route 
app.get('/:id/edit', function(req, res) {
    Business.findById(req.params.id)
    .populate('location')
    .populate('contact')
    .populate('images')
    .exec(function(err, bus) {
        if(err) {
            console.log(err);
        } else {
            res.render('edit', {bus:bus});
        }
    });
});
app.put('/:id', function(req, res) {
    Business.findByIdAndUpdate(req.params.id, req.body.bus, function(err, bus) {
        if(err) {
            console.log(err);
            res.redirect('/' + req.params.id + '/edit');
        } else {
            res.redirect('/' + req.params.id);
        }
    });
});

业务(巴士)更新良好,但 bus.location 没有更新。 商业模式

//----------------------------------------------------------------------------\\
var mongoose = require('mongoose');
//----------------------------------------------------------------------------\\
var busSchema = new mongoose.Schema({
    name: String,
    type: String,
    logo: String,
    desc: String,
    subs: Number,
    video: String,
    url: String,
    firstRun: Boolean,
    location:[ 
      {
         type: mongoose.Schema.Types.ObjectId,
         ref: 'Location'
      }
    ],
    contact:[
      {
         type: mongoose.Schema.Types.ObjectId,
         ref: 'Contact'
      }
    ],
    images:[
      {
         type: mongoose.Schema.Types.ObjectId,
         ref: 'Image'
      }
    ],
    comments:[
      {
         type: mongoose.Schema.Types.ObjectId,
         ref: 'Comment'
      }   
    ],
    created: {
       type: Date, default: Date.now
    }
});
//----------------------------------------------------------------------------\\
module.exports = mongoose.model('Business', busSchema);

位置模型

//----------------------------------------------------------------------------\\
var mongoose = require('mongoose');
//----------------------------------------------------------------------------\\
var locSchema = new mongoose.Schema(
    {
        street: String,
        city: String,
        state: String,
        zipcode: Number
    }  
);
//----------------------------------------------------------------------------\\
module.exports = mongoose.model('Location', locSchema);

【问题讨论】:

  • 欢迎来到 Stack Overflow。错误是什么?数据流如何?你能解释一下你的代码吗?在询问之前始终保持具体并尽最大努力,并且不要将 Stack Overflow 视为教程的存储库。 Stack Overflow 是一个问答网站,而不是代码编写服务。请see here学习如何写出有效的问题。

标签: node.js mongodb express mongoose


【解决方案1】:

BusinessLocationContact 是不同的集合。

findByIdAndUpdate 只更新一个集合,特别是您的集合Business。为了更新其他集合,您需要对这些集合执行操作。

如果您尝试更新“现有”位置和联系人,那么您还需要提供他们的 ID。此外,您有一个“数组”位置和联系人,因此您需要在姓名中添加 []

<% bus.location.forEach(function(location, i) { %>
    <input type="hidden" name="location[<?= i ?>][id]" value="<%= location.id %>">
    <input class="form-input" type="input" name="location[<?= i ?>][street]" value="<%= location.street %>">
    <!-- etc -->
<% }) %>

<% bus.contact.forEach(function(contact, i) { %>
    <input type="hidden" name="contact[<?= i ?>][id]" value="<%= contact.id %>">
    <input class="form-input" type="email" name="contact[<?= i ?>][email]" value="<%= contact.email %>">
    <!-- etc -->
<% }) %>

根据我(和others)的经验,我认为不可能一次更新多个文档。这意味着,在您的路由处理程序中,您将需要遍历给定数组中的每个项目并逐一更新它们。不过,另一篇文章中的答案不太正确,因为您不应该使用同步 forEach 来执行异步猫鼬操作,因为它会导致意外行为。

您需要完成三项主要任务:更新业务、更新其现有位置以及更新其现有联系人。

我喜欢使用async.js 来执行多个异步操作。在您的特定情况下,我将使用 async.series 执行每个任务,并使用 async.eachSeries 对数组的每个元素执行操作。

警告这是未经测试的,但看起来像这样:

app.put('/:id', function(req, res) {

    console.log(req.body.bus);
    console.log(req.body.location); // should be an array of objects
    console.log(req.body.contact); // should be an array of objects

    // perform each task one by one
    async.series([
        function updateBusiness (done) {
            // you need to always call the callback i.e. done to indicate the task is "done"
            // - if you pass an error as an argument, it means the task failed and stop everything
            // - otherwise, move onto the next task

            /*Business.findByIdAndUpdate(req.params.id, req.body.bus, function (err) {
                if (err) {
                    return done(err); // task failed and stop everything
                }
                done(); // task went well and proceed to the next task
            });*/

            // simplified
            Business.findByIdAndUpdate(req.params.id, req.body.bus, done);
        },
        function updateLocations (done) {
            // find and update each location
            async.eachSeries(req.body.location || [], function (location, done2) {
                Location.findByIdAndUpdate(location.id, location, done2);
            }, done);
        },
        function updateContacts (done) {
            // find and update each contact
            async.eachSeries(req.body.contact || [], function (contact, done2) {
                Contact.findByIdAndUpdate(contact.id, contact, done2);
            }, done);
        }
    ], function allDone (err) {
        // a task failed somewhere
        if (err) {
            console.log(err);
            res.redirect('/' + req.params.id + '/edit');
        // all tasks were completed
        } else {
            res.redirect('/' + req.params.id);
        }
    });
});

如果有错误,请查看控制台日志。

【讨论】:

  • 当您建议为联系人和位置添加其他 [] id 时,我能够弄清楚我的代码结构出了什么问题。我不熟悉 async.js 工具,但打算研究一下。谢谢!
  • 好奇:用你的改变,它真的只使用Business.findByIdAndUpdate 保存了吗?还是你必须做更多?
  • 是的,我可以使用 Business.findByIdAndUpdate 保存,然后在代码末尾重定向。至于联系方式和位置,我不得不单独使用 findByIdAndUpdate 和 forEach 来获得联系方式和位置。占用了更多的行,但打算弄清楚如何最好地重构它们。正如我之前所说,对此相当陌生,并且仍在学习这门手艺。但是,在您的帮助下,我能够让它工作!
猜你喜欢
  • 2017-02-10
  • 2011-12-03
  • 2012-12-23
  • 2012-06-03
  • 2015-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-08
相关资源
最近更新 更多