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

标签 javascript copy deep-copy loopbackjs

我有一个 loopback-js API。

其中我有一个产品模型,它相当复杂,有许多相关模型。 (元数据、技术要求、标签、域、目标受众……)

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

在 Loopback JS 中是否有一种简单的方法可以做到这一点?例如 product.saveAs();

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

最佳答案

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

common/mixins/duplicate.js 中的 mixin 文件

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;

更新您的模型配置:

{
"_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 功能

关于javascript - 如何在 Loopback JS 中轻松复制模型和相关模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30799706/

相关文章:

python - 实现 copy.deepcopy() 克隆函数

python:需要一个相当于破坏所有共享身份的深层复制

javascript - 为 jquery 对话框创建按钮数组

javascript - jquery .off然后恢复为on

c++ - 基类和派生类私有(private)成员变量使用

vba - 使用单元格属性将范围从一个工作表复制到另一个工作表

java - 如何制作 Java ArrayList 的深拷贝

javascript - 获取列表项的名称,单击 jquery 中的自动完成功能

JavaScript 弹出窗口/警报

python - 为什么这种复制列表的方法比其他方法快得多?