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

MongoDB大集合字段加时间戳及Eloquent集合保存技术问询

Solutions for Adding Timestamps to Nested Eloquent Collection Fields Before Saving to MongoDB

I’ve worked with Laravel + MongoDB setups quite a bit, so let’s break down how to solve your timestamp problem while optimizing that messy nested loop you’ve got going. Here are practical, actionable approaches:


1. Clean Up & Optimize Your Nested Loop

First, let’s refactor your current loop to be more readable and efficient. The goal is to avoid unnecessary array copies and make the logic easier to maintain:

$automations = Automation::all();
$updatedDocs = [];

foreach ($automations as $automation) {
    // Get the workflow data (use reference to modify in-place)
    $workflows = &$automation->workflow;

    foreach ($workflows as &$item) {
        // Add timestamps to each subscriber's fields
        if (isset($item['subscribers'])) {
            foreach ($item['subscribers'] as &$subscriber) {
                foreach ($subscriber as $key => $value) {
                    $subscriber["{$key}_updated_at"] = now();
                    // Add created_at only if it doesn't exist
                    if (!isset($subscriber["{$key}_created_at"])) {
                        $subscriber["{$key}_created_at"] = now();
                    }
                }
            }
        }

        // Add timestamps to non-subscriber fields matching your delay condition
        foreach ($item as $fieldName => &$fieldValue) {
            if ($fieldName !== 'subscribers' && is_array($fieldValue)) {
                if ($fieldValue['delay'] === "0" && $fieldValue['delay_time'] === 'now') {
                    $fieldValue['updated_at'] = now();
                    $fieldValue['created_at'] = $fieldValue['created_at'] ?? now();
                }
            }
        }
    }

    $updatedDocs[] = $automation->toArray();
}

// Use bulk upsert to minimize database round trips
Automation::upsert($updatedDocs, ['id'], ['workflow']);
  • Using references (&$variable) avoids copying large arrays, saving memory and processing time.
  • Collecting all updates first then doing a single upsert cuts down on database calls (critical for large collections).

2. Use Eloquent Mutators for Automatic Timestamps

If you’re using the jenssegers/mongodb package (the standard for Laravel-MongoDB integration), you can define mutators on your model to automatically add timestamps whenever nested fields are modified. This eliminates manual loops entirely:

use Jenssegers\Mongodb\Eloquent\Model;

class Automation extends Model
{
    protected $collection = 'automations'; // Your large MongoDB collection name

    // Automatically process workflow data when setting it
    public function setWorkflowAttribute($value)
    {
        $this->addTimestampsToNestedData($value);
        $this->attributes['workflow'] = $value;
    }

    // Recursive helper to add timestamps to all nested fields
    private function addTimestampsToNestedData(&$data)
    {
        if (!is_array($data)) return;

        foreach ($data as $key => &$value) {
            if ($key === 'subscribers') {
                foreach ($value as &$subscriber) {
                    $this->addTimestampsToNestedData($subscriber);
                }
            } else {
                if (is_array($value)) {
                    // Apply your delay condition check here
                    if (isset($value['delay'], $value['delay_time']) 
                        && $value['delay'] === "0" 
                        && $value['delay_time'] === 'now') {
                        $value['updated_at'] = now();
                        $value['created_at'] = $value['created_at'] ?? now();
                    }
                    // Recurse into deeper nested fields
                    $this->addTimestampsToNestedData($value);
                }
            }
        }
    }
}

Usage:

Now whenever you fetch and save an Automation model, the timestamps are added automatically:

$automations = Automation::all();
foreach ($automations as $automation) {
    // Any change to $automation->workflow triggers the mutator
    $automation->save();
}

3. Bulk Update Directly in MongoDB (For Large Datasets)

For collections with thousands of documents, skipping Eloquent entirely and using raw MongoDB queries is way faster. Use MongoDB’s array filters to target nested fields directly:

use Jenssegers\Mongodb\Facades\DB;
use MongoDB\BSON\UTCDateTime;

// Update non-subscriber fields matching your delay condition
DB::collection('automations')->updateMany(
    [],
    [
        '$set' => [
            'workflow.$[elem].updated_at' => new UTCDateTime(now()),
            'workflow.$[elem].created_at' => new UTCDateTime(now())
        ]
    ],
    [
        'arrayFilters' => [['elem.delay' => "0", 'elem.delay_time' => 'now']]
    ]
);

// Update all subscriber fields
DB::collection('automations')->updateMany(
    [],
    [
        '$set' => [
            'workflow.$[].subscribers.$[sub].updated_at' => new UTCDateTime(now()),
            'workflow.$[].subscribers.$[sub].created_at' => new UTCDateTime(now())
        ]
    ],
    [
        'arrayFilters' => [['sub' => ['$type' => 'object']]]
    ]
);

This approach runs directly on MongoDB, avoiding Eloquent overhead and processing all documents in bulk.


4. Key Optimization Tips

  • Batch Processing: If even bulk updates are too heavy, process documents in chunks to avoid memory exhaustion:
    Automation::chunk(100, function ($batch) {
        foreach ($batch as $automation) {
            $automation->save();
        }
    });
    
  • Lazy Loading: Fetch only the fields you need with Automation::select('id', 'workflow')->get() to reduce memory usage.
  • Avoid Overwriting Original Data: Always work with copies or references instead of modifying the original Eloquent collection directly.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:03:16