简体   繁体   English

使用Mongoose和Node.js在MongoDB中删除一对多和多对多关系中的引用

[英]Removing references in one-to-many and many-to-many relationships in MongoDB using Mongoose and Node.js

I need to mention that I am totally aware of the fact that MongoDB is not a relational database in the first place. 我需要提到的是,我完全意识到MongoDB并不是关系数据库。 However it supports referencing other documents, hence some functionality should be supported, imo. 但是,它支持引用其他文档,因此支持某些功能imo。 Anyways, I have this relationship: a Company has many Departments and one Department belongs to one Company. 无论如何,我有这种关系:一个公司has many部门,一个部门belongs to一个公司。

company.js 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 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);

Now, I am writing Node.js logic to manipulate this data using API. 现在,我正在编写Node.js逻辑以使用API​​来处理此数据。 I get that if I create a new Department, I should add a reference to Company and I should create its reference in this Company's departments array. 我知道如果创建一个新部门,则应添加对Company的引用,并应在此Company的Departments数组中创建其引用。 Simple. 简单。 But what if a user changes the Company property of a Department? 但是,如果用户更改部门的Company属性怎么办? Say, the HR Department used to belong to Company A, but a user now moves it to Company B? 假设人力资源部门曾经属于公司A,但是现在有用户将其移至公司B? We need to remove the reference to this department from Company A's array and push it to Company B. The same is when we want to delete a department. 我们需要从公司A的数组中删除对该部门的引用,并将其推到公司B。这与我们要删除部门的情况相同。 We need to find a company it belongs to and dis-associate it. 我们需要找到它所属的公司并取消其关联。 My solution is working ATM, but seems rather clumsy. 我的解决方案是在ATM上运行,但看起来很笨拙。

routes.js 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;
};

Is there any elegant solution to this case or it is just as it should be? 对于这种情况,是否有任何优雅的解决方案?

我看到您尚未掌握node.js异步本质的本质...例如,您在department.save之前有一条注释,其中说:最后……很好,早期的逻辑可能仍会在那时候...我也强烈建议您避免使用回调方法,并学习如何使用Promise做到这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM