【问题标题】:Database structure for storing nested tags and categories用于存储嵌套标签和类别的数据库结构
【发布时间】:2016-05-24 18:46:53
【问题描述】:

我正在开发一个允许我存储嵌套标签和类别的数据库,但事实证明很难找到一种相对简单的查询方式。我正在使用 Laravel,因此另一个障碍是确保它以合理的方式与 Eloquent 兼容。

目前,我尝试了两种方法。

第一种方法是创建一个名为entities 的表,其中有一个type 列,设置为tagcategory。这似乎与所使用的数据结构配合得相当好,但查询起来有点不愉快。

第二种方法是有两张表,每种类型一张。这是一场彻头彻尾的噩梦,因为这样两个表都需要有两个父列,并且无法使用正常的代码进行查询。

所以,我假设第一种方法是正确的方法。 有没有合理的方式来安排模型和数据库的迁移?以及如何准确查询数据库?这是我的模型(文件是指被标记的文件):

class Entity extends Model
{
    public function children() {
        return $this->hasMany('App\Entity');
    }
    public function parent() {
        return $this->belongsTo('App\Entity');
    }
    public function files() {
        return $this->belongsToMany('App\File')->withTimestamps();
    }
}

我的迁移(order 是一个列,可确保标签和类别显示在正确的位置,如果兄弟姐妹的话。它还应该允许我在前端使用 JavaScript 重新排列它们,这是我尚未正确研究的东西):

Schema::create('entities', function (Blueprint $table) {
    $table->increments('id')->unsigned();
    $table->integer('order');
    $table->enum('type', ['tag', 'category']);
    $table->string('name');
    $table->string('title');
    $table->text('description')->nullable();
    $table->integer('entity_id')->unsigned()->nullable();
    $table->timestamps();

    $table->foreign('entity_id')->references('id')->on('entities');
});

这是前端使用的数据结构的一个工作示例,我需要从数据库中生成它:

[
    {
        "__type": "Tag",
        "id": "water",
        "name": "Water",
        "description": "Containing water of any kind.",
        "checked": false,
        "children": [
            {
                "__type": "Tag",
                "id": "salt_water",
                "name": "Salt Water",
                "description": "Salt Water, for example in the Ocean.",
                "checked": false,
                "children": []
            },
            {
                "__type": "Category",
                "id": "fresh_water",
                "name": "Fresh Water",
                "description": "Fresh Water, such as rivers and lakes.",
                "children": [
                    {
                        "__type": "Tag",
                        "id": "river",
                        "name": "River",
                        "description": "A river of water.",
                        "checked": true,
                        "children": []
                    },
                    {
                        "__type": "Tag",
                        "id": "lake",
                        "name": "Lake",
                        "description": "A lake of water.",
                        "checked": false,
                        "children": []
                    }
                ]
            }
        ]
    },
    {
        "__type": "Category",
        "id": "species",
        "name": "Species",
        "description": "The Species of creature.",
        "featured": true,
        "children": [
            {
                "__type": "Tag",
                "id": "dog",
                "name": "Dog",
                "description": "Canis Familiaris.",
                "checked": false,
                "children": []
            },
            {
                "__type": "Tag",
                "id": "cat",
                "name": "Cat",
                "description": "Felis Catus.",
                "checked": false,
                "children": [
                    {
                        "__type": "Tag",
                        "id": "tiger",
                        "name": "Tiger",
                        "description": "A tiger.",
                        "checked": false,
                        "children": []
                    }
                ]
            }
        ]
    }
]

【问题讨论】:

  • 您的解决方案不起作用吗?我可以快速准确地看到模型如何关联子/父实体。您将需要执行一些翻译以使输出 json 匹配所需的格式。没有测试过,这看起来很可靠。
  • @j.steelman 老实说,现在我的主要问题似乎是弄清楚如何检查哪些是checked。我刚刚意识到这将是一个问题。你知道是否有办法检查哪些是通过数据透视表链接的,所以我可以将它们标记为checked: true

标签: php mysql json database laravel


【解决方案1】:

如果您的数据已经在 PHP 数组中,您可以使用这些递归函数之一

function getChecked($root)
{
    $output = [];
    if(!is_array($root) && !isset($root['children']))
    {
        $root = array($root);
    }
    foreach($root as $item)
    {
        if(isset($item['checked']) && $item['checked']) {
            if(isset($item['children']))
            {
                $children = getChecked($item['children']);
                $item['children'] = $children;
            }
            $output[] = $item;
        }
    }
    return $output;
}

function getChecked_lazy($root)
{
    $output = [];
    if(!is_array($root) && !isset($root['children']))
    {
        $root = array($root);
    }
    foreach($root as $item)
    {
        if(isset($item['children']))
        {
            $children = getChecked_lazy($item['children']);
            $item['children'] = $children;
        }
        if( (isset($item['checked']) && $item['checked']) || isset($item['children']) && !empty($item['children']))
        {
            $output[] = $item;
        }
    }
    return $output;
}

$data = [
    [
        "id" => "dog",
        "checked" => true,
        "children" => [
            [
                "id" => "wolf",
                "checked" => true,
            ],
            [
                "id" => "fox",
                "checked" => false
            ],
        ]
    ],
    [
        "id" => "cat",
        "checked" => false,
        "children" => [
            [
                "id" => "lion",
                "checked" => true
            ],
        ],
    ],
];

echo json_encode(getChecked($data), JSON_PRETTY_PRINT);
echo "\n";
echo json_encode(getChecked_lazy($data), JSON_PRETTY_PRINT);

输出:

[ { “id”:“狗”, “检查”:是的, “孩子们”: [ { “id”:“狼”, “检查”:真 } ] } ] [ { “id”:“狗”, “检查”:是的, “孩子们”: [ { “id”:“狼”, “检查”:真 } ] }, { “id”:“猫”, “已检查”:错误, “孩子们”: [ { “id”:“狮子”, “检查”:真 } ] } ]

或者你可以通过SQL查询其中checked = true,然后尝试找到根(其中parent为null)。

或者其他方式

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-27
    • 1970-01-01
    • 2012-06-26
    • 2011-04-01
    • 1970-01-01
    • 2014-01-17
    • 2011-09-27
    • 1970-01-01
    相关资源
    最近更新 更多