【问题标题】:Removing references in one-to-many and many-to-many relationships in MongoDB using Mongoose and Node.js使用 Mongoose 和 Node.js 在 MongoDB 中删除一对多和多对多关系中的引用
【发布时间】:2015-12-06 20:17:39
【问题描述】:

我需要提一下,我完全意识到 MongoDB 并不是一个关系数据库。但是它支持引用其他文档,因此 应该 支持某些功能,imo。无论如何,我有这样的关系:一个公司has many部门和一个部门belongs to一个公司。

company.js

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var CompanySchema = new Schema({
    name: {
        type: String,
        unique: true,
        required: true
    },
    departments: [{
        type: Schema.Types.ObjectId,
        ref: 'Department'
    }],
    dateCreated: {
        type: Date,
        default: Date.now
    },
    dateUpdated: {
        type: Date,
        default: Date.now
    }
});

module.exports = mongoose.model('Company', CompanySchema);

department.js

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var DepartmentSchema = new Schema({
    name: {
        type: String,
        required: true
    },
    company: {
        type: Schema.Types.ObjectId,
        ref: 'Company'
    },
    dateCreated: {
        type: Date,
        default: Date.now
    },
    dateUpdated: {
        type: Date,
        default: Date.now
    }
});

module.exports = mongoose.model('Department', DepartmentSchema);

现在,我正在编写 Node.js 逻辑来使用 API 操作这些数据。我知道如果我创建一个新部门,我应该添加对公司的引用,并且我应该在该公司的部门数组中创建它的引用。简单的。但是,如果用户更改了部门的公司属性怎么办?比方说,HR 部门以前属于 A 公司,但现在有用户把它移到 B 公司了?我们需要从A公司的数组中删除对该部门的引用,并将其推送到B公司。我们要删除一个部门时也是如此。我们需要找到它所属的公司并将其解除关联。我的解决方案是使用 ATM,但看起来相当笨拙。

routes.js

var Department = require('../../models/department'),
    Company = require('../../models/company');

module.exports = function(express) {
    var router = express.Router();

    router.route('/')
        .get(function(req, res) {
            // ...
        })
        .post(function(req, res) {
            // ...
        });

    router.route('/:id')
        .get(function(req, res) {
            // ...
        })
        .put(function(req, res) {

            // First we need to find the department with the request parameter id
            Department.findOne({ _id: req.params.id }, function(err, data) {
                if (err) return res.send(err);
                var department = data;
                // department.name = req.body.name || department.name; Not relevant

                // If the company to which the department belongs is changed
                if (department.company != req.body.company._id) {

                    // We should find the previous company
                    Company.findOne({ _id: department.company }, function(err, data) {
                        if (err) return res.send(err);
                        var company = data;

                        // Loop through its departments
                        for (var i = 0; i < company.departments.length; i++) {
                            if (company.departments[i].equals(department._id)) {

                                // And splice this array to remove the outdated reference
                                company.departments.splice(i, 1);
                                break;
                            }
                        }
                        company.save(function(err) {
                            if (err) return res.send(err);
                        });
                    });

                    // Now we find this new company which now holds the department in question
                    // and add our department as a reference
                    Company.findOne({ _id: req.body.company._id }, function(err, data) {
                        if (err) return res.send(err);
                        var company = data;
                        company.departments.push(department._id);
                        company.save(function(err) {
                            if (err) return res.send(err);
                        });
                    });
                }

                // department.company = req.body.company._id || department.company; Not relevant
                // department.dateUpdated = undefined; Not relevant

                // And finally save the department
                department.save(function(err) {
                    if (err) return res.send(err);
                    return res.json({ success: true, message: 'Department updated successfully.' });
                });
            });
        })
        .delete(function(req, res) {

            // Since we only have id of the department being deleted, we need to find it first
            Department.findOne({ _id: req.params.id}, function(err, data) {
                if (err) return res.send(err);
                var department = data;

                // Now we know the company it belongs to and should dis-associate them
                // by removing the company's reference to this department
                Company.findOne({ _id: department.company }, function(err, data) {
                    if (err) return res.send(err);
                    var company = data;

                    // Again we loop through the company's departments array to remove the ref
                    for (var i = 0; i < company.departments.length; i++) {
                        if (company.departments[i].equals(department._id)) {
                            company.departments.splice(i, 1);
                            break;
                        }
                    }
                    company.save(function(err) {
                        if (err) return res.send(err);
                    });

                    // I guess it should be synchronously AFTER everything is done,
                    // since if it is done in parallel with Department.findOne(..)
                    // piece, the remove part can happen BEFORE the dep is found
                    Department.remove({ _id: req.params.id }, function(err, data) {
                        if (err) return res.send(err);
                        return res.json({ success: true, message: 'Department deleted successfully.' });
                    });
                });
            });
        });

    return router;
};

这种情况有什么优雅的解决方案,或者它应该是这样吗?

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    我看到你还没有抓住 node.js 的异步本质的本质......例如,你在 department.save 之前有一条评论说:最后......好吧,前面的逻辑很可能是当时仍在执行...我也强烈建议您避免使用回调方法并学习如何使用承诺来做到这一点

    【讨论】:

    • 感谢您的评论!异步性质没什么大不了的,我的意思不是在算法流程的上下文中使用这个“最终”一词,而是在逻辑的上下文中使用。我知道department.save() 可能在company 模型中的引用更新之前或同时发生,它不会改变任何东西,也不会破坏应用程序的逻辑。不过,我将完全尝试采用 Promise 方法。
    猜你喜欢
    • 2015-10-25
    • 2015-12-16
    • 2014-09-25
    • 2013-11-29
    • 2020-06-12
    • 2014-01-21
    • 2014-08-15
    • 2017-04-14
    相关资源
    最近更新 更多