Дублируется запись при добавлении ее в БД

Добавляю запись в БД посредством XMLHttpRequest. Иногда записи дублируются (происходит это не часто), т.е. два раза записываются данные в таблицу при одном нажатии на кнопку «Добавить».

Подскажите, пожалуйста, как можно этого избежать или исправить?

Ниже пример моего кода:

разметка и JS
<div class="card card-info add-card">
    <div class="d-flex card-header justify-content-end align-items-center">
		<button id="btnSubmit" type="button" class="action-btn">Добавить</button>
    </div>
    <div class="card-body">
        
        <div class="div-item-info">
                <div class="item-title">Параметры</div>
                <input id="param" class="form-control form-control-course" type="number" style="width: 170px;">
        </div>

        <div class="div-item-info">
			<div class="item-title">Текст</div>
			<textarea id="paramText" class="form-control form-control-course" rows="3" style="resize: none;"></textarea>
        </div>

    </div>
</div>

<div id="insertContent"></div>

const btnSubmit = document.querySelector('#btnSubmit');
let getParam = document.querySelector('#param');
let getParamText = document.querySelector('#paramText');
let insertContent = document.querySelector('#insertContent');


btnSubmit.addEventListener('click', function(e) {
	e.preventDefault();
	
	btnSubmit.setAttribute('disabled', '');
	
	function addQuestion() {
		const formDataQuestion = 'param=' + getParam + '¶mText=' + getParamText;
		
		const xhr = new XMLHttpRequest();
		
		xhr.open('POST', '/assets/components/add-questions.php');
		xhr.responseType = 'json';
		xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		
		xhr.onload = () => {
			if (xhr.status !== 200) {
				return;
			};
			
			const response = xhr.response;
			let message = '';
			
			if (response > 0) {
				
				message = 'Успешно';
				btnSubmit.removeAttribute('disabled');
				
			} else {
				
				message = 'Что-то пошло не так :(';
				btnSubmit.removeAttribute('disabled');
			};
			
			insertContent.innerHTML = '<div class="alert alert-light small mt-5" role="alert">' + message + '</span></div>';
			
		};
		
		xhr.send(formDataQuestion);
		
	};
	
	addQuestion();
	
});

Содержимое файла add-questions.php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    
    define('MODX_API_MODE', true);
    require_once $_SERVER['DOCUMENT_ROOT'] . '/index.php';
    
    $modx->getService('error','error.modError');
    $modx->getRequest();
    $modx->setLogLevel(modX::LOG_LEVEL_ERROR);
    $modx->setLogTarget('FILE');
    $modx->error->message = null;
	
	$param = (int) $_POST['param'];
    $paramText = $modx->sanitizeString($_POST['paramText']);
    
    $countidsection = $modx->getCount('DeQuestions', array('tabl_param' => $param));
	
	$output = '';
    
    if ($countidsection == 0) {

        $dequestions = $modx->newObject('DeQuestions');
        
        $dequestions->set('tabl_param', $param);
        $dequestions->set('table_text', $paramText);
        
        if ($dequestions->save() === false) {
            $output = 0;
        };
        
        $output = 1;
        
    };

    @session_write_close();
    exit(json_encode($output));
};
Александр
08 апреля 2025, 20:38
modx.pro
112
0

Комментарии: 6

Артур Шевченко
09 апреля 2025, 10:58
0
Наверное надо добавить проверку на наличие аналогичного объекта перед созданием.
    Александр
    09 апреля 2025, 14:28
    0
    Проверка на наличие аналогичного объекта организована с помощью метода getCount:

    $countidsection = $modx->getCount('DeQuestions', array('tabl_param' => $param));
    Александр Туниеков
    09 апреля 2025, 13:19
    0
    Я обычно делаю
    if(!$obj = $modx->getObject($class,$search)){
        $obj = $modx->newObject( ...
    }
    И дублирование у меня нет. Но может потому, что у меня $search по индексированным полям ^-^.
    Нейросеть советует транзакции или
    Также, желательно добавить уникальный индекс в базе данных на поле tabl_param, что обеспечит дополнительную защиту от дублирования на уровне СУБД.
      Александр
      09 апреля 2025, 14:29
      0
      Я делаю так:

      $countidsection = $modx->getCount('DeQuestions', array('tabl_param' => $param));
              
          if ($countidsection == 0) {
          	$dequestions = $modx->newObject('DeQuestions');
          	...
          	...
          	...
          };
      И бывают дубли (

      Попробую предложенный вами вариант.

      Или вообще думаю сделать так:
      if ($countidsection == 0) {
      	// если объекта нет - создать
      	...
      	...
      	...
      } else {
      	// если есть совпадение - перезаписать значения
      	...
      	...
      	...
      };
        Александр Туниеков
        09 апреля 2025, 15:02
        0
        Для перезаписи делаю так
        if(!$obj = $modx->getObject($class,$search)){
            $obj = $modx->newObject($class);
        }
        if($obj){
            $obj->fromArray([
                'key1'=>'param1',
                 'key2'=>'param2',
            ]);
            $obj->save();
        }
          Александр
          09 апреля 2025, 15:30
          0
          Спасибо. Будем пробовать.
      Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
      6