Laravel mysql to Mongo 分享一些資料同步及分析的心得體會

jcc123發表於2021-03-17

mysql 作為業務庫,不太適合去作為分析,要不可能扛不住。先將mysql的資料同步到mongodb中,然後再從mongodb中去分析。

資料同步

將mysql中的資料同步到mongodb中,這裡分為兩步,第一步全量同步,不去檢查mongo是否存在這條資料,要不會耗時,直接插入。可以將id作為同步的校準,比如,同步過程中中斷了,此時在進行全量同步資料的時候,這樣不會導至重複插入。

$minId = OrderMongo::min('id');//基準id

Order::oldest('id')->where('id','>',$minId)->chunk(1000,function($items){
    OrderMongo::insert($items->toArray());
})

嫌插入慢的時候,可以放進佇列執行。

$minId = OrderMongo::min('id');

Order::oldest('id')->where('id','>',$minId)->chunk(1000,function($items){
    $a = $lists->pluck('id');
    $data = [
        'max' =>$a->max(),
        'min' =>$a->min()
    ];
    dispatch( new InsertQueue($data))->onQueue('insert-queue');
})

InsertQueue

 public $data;

 public function __construct($data)
    {
        $this->data = $data;
    }
 public function handle()
{
    OrderModel::oldest('id')->where('id', '>=',$this->data['min'] ))->where('id','<=',$this->data['max'])->chunk(100,function(items){
        OrderMongo::insert($items->toArray());
    });
}

記得用一個程式去消費,要不插入資料的順序會亂掉。

全量同步完後,為了保持資料的一致性,要考慮增量同步,分為插入和更新。此時根據,update_time 的時間,來對資料進行更新或插入,增量同步的時間間隔,要比定時任務的時間間隔大一分鐘。這樣可以避免在當前時間點丟單的情況,像這樣

    $schedule->command('sync:zengLiang')->everyThirtyMinutes();//30分鐘
//這裡 31分鐘
Order::where('update_time','>',now()->subMinutes(31))->each(function($item){
    OrderMongo::updateOrInsert(['id'=>$item->id,$titem->toArray());
})

資料分析

使用慣了mysql的聚合語句後,使用mongo來查會一時適應不過來,mysql 使用 join 比較多,基本上 mongo 弄明白來”join”後,使用起來就舒服多了。這裡以orders和order_items 作為例子。上程式碼

$data = OrderMongo::query()->raw(function ($collection) {
    $aggregate = [];
    $aggregate[] = [
        '$match'=>[//相當於mysql 的 where 和orWhere
            '$and'=>[
                ['date' => ['$gte' => $start, '$lt' => $end]]
            ],
            '$or'=>[
                ['store_id' => 1]
            ],
        ]
    ];
    $aggregate[] = [
        '$project' => [
            'id' =>1,//欄位展示 相當於 mysql 的 select id ,total from orders
            'store_id'=>1,
            'total'=>1,//欄位展示
        ]
    ];

    //$lookup 相當於 join 
    $aggregate [] = [
        '$lookup'=>[
            'from' =>'order_items',
            'localField'=>'order_id',
            'foreignField'=>'id',
            'as'=>'items',
        ]
    ];

    //不過這裡 查出的資料是 [[id,store_id,total,items]] items 是一個陣列,現在把它展開

    $aggregate[] = [
        '$unwind'=>'$items'
    ];

    //假如 一個order 有三條 items 這裡會展開三條資料 [[id,store_id,total,items],[id,store_id,total,items],[id,store_id,total,items]] //這裡的items 是一個物件

    //聚合
    '$group'=>[
        '_id' => [//這裡相當於 mysql 的groupBy field1,field2
            'store_id'=>'$store_id'
        ],
        'store_total' => [
            '$sum' => '$total',
        ],//相當於 select sum(total) as store_total //這裡並不是門店的資料,因為 oreder_items 展開了,只是作為示例

    ];
    return $collection->aggregate($aggregate);


})

這只是最基礎的分析資料,分析的時候,可以將各個維度的模組分析資料,分開,模擬資料弄的多一點,放進佇列跑,跑得快點,跑錯了沒關係,刪除掉資料重新跑。可能最後總資料只差了10 幾款錢,這時不要慌,先確定範圍,再將範圍一步步的縮小,最後找到造成資料錯誤的一條資料和幾條資料,修復,在和基準資料確認,再跑~總之就是不斷跑~~因為這一條資料錯誤,假如後面的資料依賴這條資料的話,那麼資料多多少少會有一點誤差

以上

待定

可能會寫一個資料同步的擴充套件包,因為寫的過程中,發現可以結構化,這樣在後臺點點點就可以同步了

本作品採用《CC 協議》,轉載必須註明作者和本文連結
NOT IS BECAUSE I WANT TO WRITE, BUT I WANT TO INCREASE, SO I GO TO WRITE~~

相關文章