Home > Net >  Laravel 8.x - How to use updateOrCreate with a where clause?
Laravel 8.x - How to use updateOrCreate with a where clause?

Time:11-26

I am trying to use Laravel updateOrCreate to update a record if its within this month and last month based on if an ID exists.

\App\Models\Result::updateOrCreate(
        [
            'id' => $request->get('id'),
            // where created_at is within the last 2 months
            'created_at' => [
                '>',
                \Carbon\Carbon::now()->startOfMonth()->subMonthsNoOverflow()
            ],
        ],
        [
            'discipline_one' => $request->get('d-one'),
            'discipline_two' => $request->get('d-two'),
            'discipline_three' => $request->get('d-three'),
            'discipline_four' => $request->get('d-four'),
            'discipline_five' => $request->get('d-five'),
            'discipline_six' => $request->get('d-six'),
        ]
    );

If the ID exists, and the result is in this current month or last, a new record is created instead of updated.

Expected input: 1 (which exists from last month)
Expected output: Record is updated

Expected input: 2 (which doesn't exist or is not within 2 months)
Expected output: New record is created

Update:

Using the answer suggested,

'id' => $request->get('id'),
'created_at' => \App\Models\Result::whereBetween('created_at', [
    \Carbon\Carbon::now()->startOfMonth()->subMonthsNoOverflow(),
    \Carbon\Carbon::now()->endOfMonth(),
]),

I get the error:

Object of class Illuminate\Database\Eloquent\Builder could not be converted to string

CodePudding user response:

Here you go:

You only need to explicitly define the operators in the method's first parameter.

Each element of the array in the method's first parameter should be an array containing the three arguments.
column, operator, value

$startDate = \Carbon\Carbon::now()->startOfMonth()->subMonths(2);
$endDate = \Carbon\Carbon::now()->endOfMonth();

$resultRow = \App\Models\Result::query()
        ->where('id', $request->id)
        ->whereBetween('created_at', [$startDate, $endDate])
        ->first();

\App\Models\Result::updateOrCreate(
    [
        [
            'id', '=', $request->get('id'),
        ],
        [
            'created_at', '>=', $startDate,
        ],
        [
            'created_at', '<=', $endDate,
        ],
    ],

    array_merge(
        [
            'discipline_one' => $request->get('d-one'),
            'discipline_two' => $request->get('d-two'),
            'discipline_three' => $request->get('d-three'),
            'discipline_four' => $request->get('d-four'),
            'discipline_five' => $request->get('d-five'),
            'discipline_six' => $request->get('d-six'),
        ],

        $resultRow ? [] : [
            'id' => $request->get('id'),
            'created_at' => \Carbon\Carbon::now()
        ]
    )

);

Notice that I repeated id & created_at column settings in the method's second parameter. It's because contrary to the regular behaviour, a merge of the 2 method's parameter arrays wasn't performed based on my tests if no result was found with that criteria.

  • Related