首页 文章

如何在Loopback JS中轻松复制模型和相关模型

提问于
浏览
4

我有一个loopback-js API .

在其中我有一个相当复杂的产品模型,有许多相关的模型 . (元数据,技术要求,标签,域名,targetAudience,......)

我正在编写CMS,我希望用户能够轻松地复制产品,然后只需更改一些小东西,因为所有这些产品的许多数据都是相同的 .

在Loopback JS中有一个简单的方法吗?例如 product.saveAs();

我看到的唯一方法是从产品中获取数据,然后删除id并将数据作为新产品插入数据库中,然后对所有相关模型执行相同操作...

1 回答

  • 4

    由于我在网上找不到简单的答案,我想出了一个可以用模型实现的mixin . mixin定义了一个重复方法,它通过检查模型定义来复制模型,因此它遍历关系树,复制或链接相关项:

    mixin file in common/mixins/duplicate.js

    var async = require('async');

    function Duplicate(Model){
    
        Model.duplicate = function (id, cb) {
            var self = this;
            var models = Model.app.models;
            var includeRelations = Object.keys(self.definition.settings.relations);
    
            self.findById(id, {include: includeRelations}, function(err, fromInstance){
                if(err){
                    return cb(err);
                }
    
                var fromData = JSON.parse(JSON.stringify(fromInstance));
                delete fromData.id;
                self.create(fromData, function(err, newInstance){
                    if(err){
                        return cb(err);
                    }
                    var relations = self.definition.settings.relations;
                    var operations = [];
                    for(var relationName in relations){
                        var relation = relations[relationName];
                        switch(relation.type){
                            case "hasAndBelongsToMany": //add extra links to relation
                                if(relation.foreignKey == "") relation.foreignKey = "id";
                                for(var i = 0; i < fromData[relationName].length; i++){
                                    var relatedItem = fromData[relationName][i];
                                    operations.push(async.apply(newInstance[relationName].add, relatedItem[relation.foreignKey]));
                                }
                                break;
                            case "hasMany": //create extra items
                                if(relation.through){
                                    //don copy many through relations, add an extra has many on the intermediate
                                } else {
                                    // copy ze shit, and recursively check if child relations have to be duplicated
                                    for(var i = 0; i < fromData[relationName].length; i++) {
                                        var relatedItem = fromData[relationName][i];
    
                                        operations.push(async.apply(
                                            function(relation, relatedItem, newInstance, cb2){
                                                try {
                                                    models[relation.model].duplicate(relatedItem.id, function(err, duplicatedInstance){
                                                        if(err){
                                                            cb2(err);
                                                        }
                                                        var fk = relation.foreignKey || self.definition.name.substr(0, 1).toLowerCase() + self.definition.name.substr(1) + "Id";
                                                        duplicatedInstance.updateAttribute(fk, newInstance.id , cb2);
                                                    });
                                                } catch(err){
                                                    cb2(err);
                                                }
                                            },
                                            relation, relatedItem, newInstance));
                                    }
                                }
                                break;
                            default: //do nothing
                        }
                    }
    
                    if(operations.length > 0){
                        async.parallel(operations, function (err, results) {
                            if (err) cb(err);
                            cb(null, newInstance);
                        });
                    } else {
                        cb(null, newInstance);
                    }
                });
            })
        }
    }
    
    module.exports = Duplicate;
    

    Update your model-config:

    {
    "_meta": {
      "sources": [
        "loopback/common/models",
        "loopback/server/models",
        "../common/models",
        "./models"
      ],
      "mixins": [
        "loopback/common/mixins",
        "../common/mixins"
      ]
    },
    

    Define in model where needed, that you want to use the mixin:

    ...
    "acls": [
        {
           "accessType": "*",
            "principalType": "ROLE",
            "principalId": "$everyone",
            "permission": "DENY"
        }
    ],
    "methods": [],
    "mixins": {
      "Duplicate": true
    }
    

    Use at own risk

    它远非完美,但就目前而言,它足以满足我的需求 . 也许其他人也可以使用它 .

    目前它复制模型数据本身(包括belongsTo关系的外键和嵌入模型),hasMany(递归)和hasToAndBelongsToMany(非递归) . 如果你想要hasManyThrough功能,最好在'through-table'中添加一个额外的hasmany-relation,它将被复制 .

    Things I might add in the future:

    • 检查是否在有效的Loopback模型上调用mixins

    • 添加选项以指定应包含哪些关系

    • 添加has-many-through功能

相关问题