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

时间:2015-06-12 09:28:30

标签: javascript copy deep-copy loopbackjs

我有一个loopback-js API。

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

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

在Loopback JS中有一种简单的方法吗? E.g product.saveAs();

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

1 个答案:

答案 0 :(得分:4)

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

共同的mixin文件/ 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;

更新您的model-config:

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

在需要的模型中定义,您要使用mixin:

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

自担风险使用

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

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

我将来可能添加的内容:

  • 检查是否在有效的环回模型上调用mixins
  • 添加选项以指定应包含哪些关系
  • 添加has-many-through功能