You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel后台用户评论内容重复但ID和日期不同问题求助

问题分析

你的代码目前仅通过review_submitted_at与数据库中最后一条评论的日期对比来决定是否插入,但App Store Connect API中,用户编辑评论可能会生成新的customerReview条目(新的review_id和createdDate);如果编辑后的评论内容与原评论一致,就会导致数据库中出现内容相同但ID、日期不同的重复条目。另外,仅依赖日期判断也可能因为API分页逻辑(比如单次返回的200条中包含了之前未抓取到的旧评论,但日期仍晚于某次的lastDate)引发重复。

解决方案

1. 数据库层面添加唯一约束(底层防护)

在reviews表中,给app_id和review_id添加组合唯一索引,确保同一个App下的同一个review_id(App Store返回的评论唯一标识)不会被重复插入:

ALTER TABLE reviews ADD UNIQUE INDEX idx_app_review_id (app_id, review_id);

这是最可靠的底层防护,即使代码逻辑有疏漏,数据库也会直接拒绝重复插入操作。

2. 修改代码逻辑,基于review_id判断是否已存在

替换当前仅靠日期判断的逻辑,改为先检查review_id是否已存在于数据库中:

public function storeReviewsInDB($appId, $reviews)
{
    $customerReviews = $reviews->data ?? [];
    $app = DB::select('SELECT id, name FROM apps WHERE app_store_id = ?', [$appId]);
    $appId = $app[0]->id;

    // 批量获取已存在的review_id,减少数据库查询次数
    $existingReviewIds = DB::table('reviews')
        ->where('app_id', $appId)
        ->pluck('review_id')
        ->toArray();

    $insertData = [];
    foreach ($customerReviews as $customerReview) {
        $reviewId = $customerReview->id;
        // 先判断当前review_id是否已存在
        if (!in_array($reviewId, $existingReviewIds)) {
            $reviewSubmittedAt = gmdate('Y-m-d H:i:s', strtotime($customerReview->attributes->createdDate));
            $responseId = $customerReview->relationships->response->data->id ?? null;
            
            $insertData[] = [
                'app_id' => $appId,
                'review_id' => $reviewId,
                'author_name' => $customerReview->attributes->reviewerNickname,
                'title' => $customerReview->attributes->title,
                'body' => $customerReview->attributes->body,
                'rating' => $customerReview->attributes->rating,
                'country' => $customerReview->attributes->territory,
                'review_submitted_at' => $reviewSubmittedAt,
                'response_id' => $responseId
            ];
            // 将已处理的review_id加入列表,避免循环内重复判断
            $existingReviewIds[] = $reviewId;
        }
    }

    if (!empty($insertData)) {
        DB::table('reviews')->insert($insertData);
    }
}

3. 使用Laravel的upsert方法(支持评论更新)

如果希望在用户编辑评论时,能同步更新数据库中的内容(而不是只插入新评论),可以使用Laravel的upsert方法,它会自动判断记录是否存在:存在则更新,不存在则插入:

public function storeReviewsInDB($appId, $reviews)
{
    $customerReviews = $reviews->data ?? [];
    $app = DB::select('SELECT id, name FROM apps WHERE app_store_id = ?', [$appId]);
    $appId = $app[0]->id;

    $upsertData = [];
    foreach ($customerReviews as $customerReview) {
        $reviewSubmittedAt = gmdate('Y-m-d H:i:s', strtotime($customerReview->attributes->createdDate));
        $responseId = $customerReview->relationships->response->data->id ?? null;
        
        $upsertData[] = [
            'app_id' => $appId,
            'review_id' => $customerReview->id,
            'author_name' => $customerReview->attributes->reviewerNickname,
            'title' => $customerReview->attributes->title,
            'body' => $customerReview->attributes->body,
            'rating' => $customerReview->attributes->rating,
            'country' => $customerReview->attributes->territory,
            'review_submitted_at' => $reviewSubmittedAt,
            'response_id' => $responseId
        ];
    }

    if (!empty($upsertData)) {
        DB::table('reviews')->upsert(
            $upsertData,
            ['app_id', 'review_id'], // 唯一标识字段(需对应数据库的唯一索引)
            ['author_name', 'title', 'body', 'rating', 'country', 'review_submitted_at', 'response_id'] // 需要更新的字段
        );
    }
}

使用upsert必须确保数据库中已经添加了app_id和review_id的唯一索引,否则会报错。

额外优化:处理API分页

当前API请求仅使用limit=200和排序,没有处理分页逻辑,当评论总数超过200条时,可能会漏掉旧评论或者重复抓取。App Store Connect API支持通过cursor参数分页,你可以从API响应的links.next中获取下一页的URL,循环抓取直到没有更多评论,确保所有评论都被正确抓取且不会重复。

内容的提问来源于stack exchange,提问作者Ashish Pithava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 11:37:37