用于存储嵌套标签和类别的数据库结构

时间:2016-05-24 18:46:53

标签: php mysql json database laravel

我正在开发一个允许我存储嵌套标签和类别的数据库,并且很难找到一种相对简单的查询方式。我正在使用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": []
                    }
                ]
            }
        ]
    }
]

1 个答案:

答案 0 :(得分:0)

如果你的数据已经在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": "dog",
        "checked": true,
        "children": [
            {
                "id": "wolf",
                "checked": true
            }
        ]
    }
]
[
    {
        "id": "dog",
        "checked": true,
        "children": [
            {
                "id": "wolf",
                "checked": true
            }
        ]
    },
    {
        "id": "cat",
        "checked": false,
        "children": [
            {
                "id": "lion",
                "checked": true
            }
        ]
    }
]

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

或其他方式