前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >迁移 valine 评论数据至 wordpress 数据库

迁移 valine 评论数据至 wordpress 数据库

作者头像
2Broear
发布2024-03-12 10:40:42
820
发布2024-03-12 10:40:42
举报
文章被收录于专栏:2B博客2B博客

前言

老早就计划着这件事了,知道长期使用第三方提供的数据服务可能那天就会挂掉的几率(比如之前的leancloud限制云引擎及域名回收事件),放在第三方或多或少会影响到部分使用其免费服务的群体,但毕竟人家是免费提供到的服务,我们白嫖的就不要在这里说三道四了,只是就事论事来讲数据还是存放在自己的手中最安全可靠。

数据迁移

一直以来leancloud都提供了数据导出服务,格式为 json line(jsonl),这里其实很方便了,因为市面上大多数评论系统都可以json格式的数据进行导入迁移数据,也就是说我们只需要把导出的 jsonl 格式转为 json 即可兼容大部分评论系统。此前为有考虑过 twikoo 评论,因其部署在 vercel 也比较放心,但无奈导入评论时报错没找到原因,故搁置。

此前开源主题时已经做了 wordpress 评论兼容,只是没有把魔改valine上的ui及功能移植过去,现在也就打算将存放于 leancloud 的 valine 评论数据导入到 wordpress 数据库内,一个为了做备份(几千条数据万一丢了就不好了,虽然经常有在导出备份),另一个就是想后期把 wordpress 评论给改一下,以后如果 leancloud 不再提供服务时就用 wp 评论平替,算是一个备选方案。

这里在做个备份及导入规则等操作记录,方便以后查阅。

数据更新(前提)

在导入 mysql 前,如果有些 valine 生成(或者我们自定义的)的数据项我们不想要(如 ACL/isNotified 等等),这时候我们需要将 jsonl 格式转为 json 格式( convertjson.com可在线转换)。

使用本地编辑器打开 .jsonl 文件删掉第一行的 filetype:JSON-streaming {"type":"Class","class":"Comment"}ctrl+f 查找 }+换行符ctrl+enter\n)替换为 },+换行符,最后使用 [] 将所有对象包裹即可。

利用正则表达式将评论数据中那些不需要的数据一一项剔除掉,下方存档参考用。注意:必须将 ACLinsertedAt 两个数据删掉,否则可能影响后续数据转换操作!tips:貌似 leancloud 导出数据时无法自定义列及删除上述两列

代码语言:javascript
复制
","ACL".*?\}\},"       //访问控制对象
","insertedAt".*?\},"  //插入时间对象
","  //以上替换

"updatedAt".*?,"       //更新时间对象
","  //替换
","isNotified".*?\}    //已发件提醒
"}   //替换

//自定义对象
,"md5mail".*?,"
,"mailMd5".*?,"
,"ip".*?,"
,"ads".*?,"
,"  //以上替换
,"topset":.*?\},
},  //替换
"isEdited".*?,"
"   //替换

<p><a class=\\"at\\".*?/a> , // 替换评论中所有 @人员 信息为空(wp函数加载评论时自动添加@人员)

数据转换(参考)

可无视在线数据转换操作,所有 json to sql 均可在 phpmyadmin 及参考下方数据关联的 navicat 软件中进行数据转换操作

众所周知 wordpress 使用的是 mysql 数据库,那么json是不能直接用的,所以需要再到上述网站将 json 转换为 sql 格式,最后在 phpmyadmin 中导入 sql 数据到 wordpress 数据库。注意:此处数据转换需上外网访问,否则第二步(Step 2: Choose output options)时无法加载出数据导出选项!

此处可无视 key 值选项,后面需要自定义 comment_ID 为主键

完成 json 到 sql 到转换后,将转换后的 sql 文件下载到本地,根据 wp 数据库中自带的 wp_comments 数据表结构进行进一步编辑,以下是我的编辑参考(务必提前将 wp_comments 数据表结构更改为上面转换好的结构)可以先拟个表(valine2wp)导入测试正常上传后,再做其他操作。注意:此处需手动新增设置 comment_ID 字段为递增及主键,否则可能影响后续操作。

代码语言:javascript
复制
DROP TABLE IF EXISTS valine2wp;
CREATE TABLE IF NOT EXISTS valine2wp(
   comment_ID           BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY
  ,comment_author       VARCHAR(11) NOT NULL
  ,updatedAt            DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00'
  ,objectId             VARCHAR(24) NOT NULL
  ,comment_author_email VARCHAR(30)
  ,comment_agent        VARCHAR(418) NOT NULL
  ,comment_date         DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00'
  ,md5mail              VARCHAR(32)
  ,comment_author_url   VARCHAR(57)
  ,comment_content      VARCHAR(85226) NOT NULL
  ,url                  VARCHAR(50)
  ,comment_post_ID      BIGINT(20) DEFAULT 0
  ,rid                  VARCHAR(24)
  ,comment_karma        INT(11) NOT NULL DEFAULT 0
  ,comment_approved     VARCHAR(20) NOT NULL DEFAULT 1
  ,comment_type         VARCHAR(20) NOT NULL DEFAULT 'comment'
  ,comment_parent       BIGINT(20) NOT NULL DEFAULT 0
  ,user_id              BIGINT(20) NOT NULL DEFAULT 0
    );

当一切正常导入并正常运行后,此时我们需要进行下一步操作评论数据之间的关系(在 Step 3: Generate output 时如果是测试表可以选第一个 JSON To SQL Insert,如果是更新 wp_comments 表可以选第二个 JSON To SQL Update需要注意的是如果存在原生 wp_comments 表内没有的字段,则需在 wp_comments 表内新建或在 Step 3 生成 sql 时前取消勾选该字段 Include 选项)。

数据关联(主要)

在关联数据时,我们需要解决以下2个问题:

  1. valine/wordpress 是如何关联评论数据到对应页面的?
  2. valine/wordpress 是如何关联子评论数据到父评论的?

首先, valine 中通过查看源码或 leancloud 数据结构可以看到评论数据是通过页面 url 来进行关联的,而 wordpress 在其评论数据表中是通过 comment_post_ID 字段来分别对应到各文章 id 的。其次,valine 是通过每条评论中的 objectidrid(reply objectId 主楼) pid(parent objectId 楼中楼) 字段的对应关系来进行父/子评论关联,而 wordpress 则直接在评论数据表中通过 comment_parent(默认 0)字段来关联其对应其评论的 comment_ID 字段。

了解完双方评论的基本原理后,就可以上手操作关联数据了。

关联文章页面

首先我们需要利用 valine 中提供的 url 字段来分别匹配 wordpress 数据库中对应的文章 slug 别名的文章id(也就是把 url 转换为其文章对应的 comment_post_ID),这里我是写了个简单的 php 文件来读取 json 文件并遍历获取每个对象的对应文章 id 后再写入 json 进行新增的(很傻,而且速度不快),其实这里可以直接在 phpmyadmin 中使用 mysql 语句进行批量替换的,就不用这么麻烦了!虽然是个笨办法,不过也还能用,简单做个记录(在wp根目录创建以下php文件,再将之前转换后的 json 数据丢到根目录访问即可。一点需要注意的是需要修改 $url 变量规则为你自己的 url 别名匹配规则)。

代码语言:javascript
复制
<?php
    define('WP_USE_THEMES', false);  // No need for the template engine
    require_once( 'wp-load.php' );  // Load WordPress Core

    // 通过文章别名模糊匹配文章id
    function get_post_like_slug($post_slug) {
        global $wpdb;
        $post_slug = '%' . $post_slug . '%';
        $pid = $wpdb->get_var($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_name LIKE %s", $post_slug));
        return get_post($pid);
    };
    global $wpdb;  //使用 wpdb 查询所有文章id
    $wp2valine = $wpdb->get_results("SELECT url FROM wp2valine WHERE 1 ORDER BY comment_ID ASC"); 
 
    //读取同目录 json 文件
    $filename = "jsonl2json.json";
    $handle = fopen($filename, "r");  //读取二进制文件时,需要将第二个参数设置成'rb'
    $contents = fread($handle, filesize ($filename));  //通过filesize获得文件大小,将整个文件一下子读到一个字符串中
    fclose($handle);

    // 写入文章 id 到每个 json 对象
    $decode = json_decode($contents);  //解码 json
    foreach ($wp2valine as $index => $res){
        $urs = $res->url;
        $url = substr($urs, strpos($urs, '_')+1, strlen($urs));  //注意??修改此规则为你文章 url 别名规则
        $uid = get_post_like_slug($url)->ID;
        array_push($comment_post_ID, $uid);
        $decode[$index]->comment_post_ID = $uid;
    };

    // 输出新的 json 文件
    ob_start();
    print_r(json_encode($decode,JSON_UNESCAPED_UNICODE));  //使用 JSON_UNESCAPED_UNICODE 参数来正确输出 emoji 表情
    $content = ob_get_contents();
    ob_end_clean();
    file_put_contents(ABSPATH . '/output.json', $content);
?>

完成上述操作后,应该能在wp根目录看到生成的 output.json 文件,打开会发现每条 json 对象已经新增对应的 comment_post_ID 文章id对象;再之后将 output.json 在 convertjson.com/json-to-sql 转换为 sql 数据库文件后重新导入到 wordpress 数据库查看运行测试。

??注意!确保非 null 字段不存在 null 值!

关联父级评论(注意项)

完成评论数据文章关联后就剩最后一步了,关联子评论到父级评论,利用上面提到的原理操作即可,这次我选择直接使用 mysql 进行数据库更新,这样就告别了繁琐的读写删改 json 及转换步骤了。下面是实现评论关联的 mysql 条件语句及示意图(部分选中数据仅作观察对比)。

原理很简单, 通过对比评论数据表中的 objectidpid 字段,如果相同则表示其为父子关系(提取符合的所有数据行),然后提取父级(objectid)的 comment_ID 字段将其写入到 pid 数据行(子评论)中的 comment_parent 字段即可

此图已不再适用,需替换 rid 为 pid 来关联 objectId 评论父级

将符合 2617 评论的所有 rid 行设置其 comment_parent 为父评论的 comment_ID 2617

??注意??不可直接上传已转换 json 的 sql 文件到服务器上的 wp_comments 数据表执行 comment_parent 数据关联,这样会导致 wordpress 评论数据表发生改变!会影响 comment_parent 字段写入成功后续 wordpress 无法正常读取!我们需要在本地完成所有 comment_parent 字段的 sql 数据关联操作,可参考以下方案。

操作环境: windows mysql + navicat for mysql(留意当前需处理的 sql 文件数据结构必须与 wordpress 数据库中导出 wp_comments 数据表保持一致!)建议提前在原数据库内重新设计表,新增 objectIdpiduid 等字段再导出,参考 sql 语句

代码语言:javascript
复制
ALTER TABLE `wp_comments` ADD `objectId` VARCHAR ( 24 ) CHARACTER 
SET utf8mb4 COLLATE utf8mb4_unicode_520_ci NOT NULL AFTER `user_id`,
ADD `pid` VARCHAR ( 24 ) CHARACTER 
SET utf8mb4 COLLATE utf8mb4_unicode_520_ci NOT NULL AFTER `objectId`,
ADD `rid` VARCHAR ( 24 ) CHARACTER 
SET utf8mb4 COLLATE utf8mb4_unicode_520_ci NOT NULL AFTER `pid`,
ADD `url` VARCHAR ( 255 ) CHARACTER 
SET utf8mb4 COLLATE utf8mb4_unicode_520_ci NOT NULL AFTER `rid`;
代码语言:javascript
复制
<?php
    //... UTC时间格式化参考
    foreach ($decode as $index => $res){
        $utc_date = $decode[$index]->comment_date;
        $utc2date = date('Y-m-d H:i:s',strtotime($utc_date));
        $decode[$index]->comment_date = $utc2date ? $utc2date : '0000-00-00 00:00:00';
    }
    //...
?>
  1. 首先将 wordpress 数据库中的 wp_comments 数据表新增字段后导出 sql 文件。
  2. 然后在 navicat mysql 编辑器中右键运行 sql 文件导入 wp_comments.sql 文件(需要将原有数据删除,在设计表选项卡中将自动递增设置为1),之后将已关联 commetn_post_ID 字段的 json 文件导入到刚加载的 sql 文件中(??注意 json 中的 comment_date 日期字段如果是 utc 格式需要使用 php 函数 date(‘Y-m-d H:i:s’,strtotime($utc_date)) 转换为普通日期格式 Y-m-d H:i:s 后再导入到 sql 文件,参考上方UTC时间格式化)??注意:若导入时候数据映射步骤显示不全,则表示 json 对象中的首行中未包含缺失的数据 key,导入数据首行必须包含所有所需字段(包括””空值),否则导入后将缺失该字段 value 值)
  3. 执行下方 sql 语句通过对比 pidobjectId 值将 comment_parent_ID 关联至 comment_ID。(2k+数据执行时长大概在 5s)
  4. 导入完成后将处理好的数据表右键转储为 sql 文件(包含数据和结构)导出为 sql 后再导入到 wordpress 数据库即可覆盖 wp_comments 数据表即可。
代码语言:javascript
复制
# 注意执行 SELECT ... FOR UPDATE 时无法模拟执行,请提前备份好数据再操作!
SELECT
	objectId.comment_parent,
	objectId.pid,
	pid.comment_ID,
	pid.objectId 
FROM
	`wp_comments` objectId,
	`wp_comments` pid 
WHERE
	objectId.pid = pid.objectId FOR UPDATE;  #保留分号否则报错
UPDATE `wp_comments` objectId,
       `wp_comments` pid 
SET objectId.comment_parent = pid.comment_ID 
WHERE
	objectId.pid = pid.objectId

#可选执行(更新评论GMT时间)
UPDATE `wp_comments` SET comment_date_gmt = DATE_SUB(comment_date,INTERVAL 8 HOUR) WHERE 1  #计算GMT时差(DATE_SUB()和DATE_ADD()函数)

一开始我查了很久,因为不知道单表多字段查询如何通过 update 直接修改,所以选择使用 select for update 进行修改,测试可用,速度也很快。需要注意的就是 for update 后 update 的时候也需要带上 WHERE 条件(同 select 条件),否则修改后 comment_parent 全部变成 1..

关联评论数量

完成上述操作后导入 wordpress 的 mysql 数据库应该就能在对应文章/页面中加载出对应评论了,下面是统计文章评论数量,需要先把 wp_posts 表导出至本地(注意备份)。在 valine 中可直接通过 xhr 请求的 json 对象返回长度判断评论数量,而 wordpress 中则是储存在 wp_posts 数据表中的 publish(已发布) 页面/文章下的 comment_count 字段中,这里我们通过交叉查询(cross join)来实现 mysql 中两表数据的查询及更新操作

使用 GROUP BY 将查询到符合 wp_posts/wp_comments 中符合条件的 COUNT(*) 数量 CROSS JOIN 交叉合集为 res 表,然后对比 res 表 ID 及 wp_posts 表 ID,最后将 res 表中的 count 写入 wp_posts 中的 comment_count

代码语言:javascript
复制
UPDATE `wp_posts` t1,
       `wp_comments` t2
CROSS JOIN (
	SELECT
		ID,
		COUNT(*) AS cnt 
	FROM
		`wp_posts` t1,
		`wp_comments` t2 
	WHERE
		t1.post_status = "publish" 
		AND t2.comment_post_ID = t1.ID 
	GROUP BY
		t2.comment_post_ID 
	) AS res 
SET t1.comment_count = res.cnt 
WHERE
	t1.ID = res.ID 
	AND t1.post_status = "publish";
#!在 WHERE 条件中需要对比目标 table id 及查询结果 table id,否则执行更新后都是同一个数值
#需要在交叉查询时返回查询结果 id 用作 update 更新时的条件

小结

这次数据迁移持续了几天,总的来说还是比较满意,至少成功把数据对接好了嘛~还了解了几个 mysql 语法顺便也拓展了下 php 处理 json 数据之间的方案。

1122更新,近几天来来回回修订了好几个版本,现在算是确定了。一开始的 phpmyadmin 转 sql to json 再处理 json 转 sql 再到在线网站设计 sql 数据表后导入 wordpress,到现在直接使用 navicat 编辑、设计、导入转出全程本地化处理(总感觉太依赖线上服务不太好,万一以后要再做迁移不能用就麻烦了),处理数据的逻辑更清晰了,顺便只保留了几个与 valine 关联的字段方便以后使用。一个建议的话就是导入数据能在本地处理的就不要到线上使用 sql 处理,否则可能引发一系列不可预料的问题。毕竟数据提供好了,才方便数据库处理。

1129更新,处理完评论数量数据关联总算是告一段落了..

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-03-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 数据迁移
  • 数据更新(前提)
  • 数据转换(参考)
  • 数据关联(主要)
    • 关联文章页面
      • 关联父级评论(注意项)
        • 关联评论数量
        • 小结
        相关产品与服务
        数据库
        云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
        http://www.vxiaotou.com