vincent15000's avatar

JSON fields to update only subkeys if present in the body

Hello,

I have a table with a JSON field named config.

It can contain some properties.

{
	menu: [
		...
	],
	other: {
		name: 'David',
		data: 'Hello world',
	}
}

Some put requests will update the config field.

Each put request contains a body property, which is an object containing all new values to update.

If the request does contain the menu property in the $body->config value, then the menu has to be updated in the database (config field).

If the request doesn't contain the menu property in the $body->config value, then the menu must not be updated in the database.

Here is the current code.

$fieldsToUpdate = [];

foreach ($body->payload as $key => $value) {
    if (in_array($key, ['input_bandwidth', 'output_bandwidth', 'config'])) {
        if ($value) {
            $fieldsToUpdate[$key] = $value;
        }
    }
}

$infrastructure = Infrastructure::firstOrCreate([
    'name' => $body->payload->infrastructure_name,
]);

$port = Port::updateOrCreate([
    'name' => $body->payload->name,
    'infrastructure_id' => $infrastructure->id,
], $fieldsToUpdate);

How can I adapt this code to update or not some subkeys of the config field ?

Thanks for your help.

V

0 likes
6 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

To achieve the desired functionality of updating only specific subkeys of the config field in the database, you can use Laravel's ->json() method to update JSON columns. Here's how you can adapt your code to handle this:

  1. Check if the config key exists in the request body.
  2. Merge the existing config data with the new data from the request body.
  3. Update the config field in the database with the merged data.

Here's the updated code:

$fieldsToUpdate = [];

foreach ($body->payload as $key => $value) {
    if (in_array($key, ['input_bandwidth', 'output_bandwidth', 'config'])) {
        if ($key === 'config' && is_array($value)) {
            // Fetch the existing config from the database
            $existingConfig = $port->config ?? [];

            // Merge the existing config with the new values
            $mergedConfig = array_merge($existingConfig, $value);

            // Add the merged config to the fields to update
            $fieldsToUpdate[$key] = $mergedConfig;
        } else {
            if ($value) {
                $fieldsToUpdate[$key] = $value;
            }
        }
    }
}

$infrastructure = Infrastructure::firstOrCreate([
    'name' => $body->payload->infrastructure_name,
]);

$port = Port::updateOrCreate([
    'name' => $body->payload->name,
    'infrastructure_id' => $infrastructure->id,
], $fieldsToUpdate);

Explanation:

  1. Check for config key: The code checks if the config key is present in the request body and if it is an array.
  2. Fetch existing config: It fetches the existing config data from the database. If the config field is null, it initializes it as an empty array.
  3. Merge configs: It merges the existing config data with the new data from the request body.
  4. Update fields: It adds the merged config data to the $fieldsToUpdate array.
  5. Update or create: Finally, it updates or creates the Port record with the updated fields.

This approach ensures that only the specified subkeys in the config field are updated, while the other subkeys remain unchanged.

vincent15000's avatar

@Tray2 Yes thank you, I know your post on your website.

But in my case I really couldn't do else than having a JSON field.

The config field will contain some various and not predictable contents coming from many different microservices.

Tray2's avatar

@vincent15000 I'm a bit allergic toward microservices, I prefer a more monolithic approach.

1 like
vincent15000's avatar

@Tray2 I'm not really competent with microservices, I just developed the core application which uses the functionalities of different microservices. And it was a choice / constraint of the company.

And now I fully understand that it wasn't possible to do another way, the microservices were unavoidable in this project.

Well ... it's was good experience ... but I share your opinion and I prefer a monolithic approach too.

amitsolanki24_'s avatar

@vincent15000

Check this chatgpt response

1 like

Please or to participate in this conversation.