Как сохранить буквенно-цифровую последовательность в mongodb и начать генерацию с последней сохраненной последовательности в MongoDB

У меня есть метод, который генерирует буквенно-цифровую последовательность на основе определенного шаблона. Я хочу сохранить сгенерированную последовательность, и когда в следующий раз я захочу создать новую, она должна начинаться с последней сохраненной. У меня проблема с этим, потому что это буквенно-цифровой. Кроме того, я хочу поместить сгенерированные идентификаторы в файл Excel.

Эти два метода ниже проверяют, существует ли он уже, а также пытаются получить последний сохраненный элемент.

 public Optional<Terminal> findByGeneratedTerminalIDs(String id){
        return Optional.ofNullable(this.collection.findOne(Filters.eq("generatedTerminalID", id)));
    }

    public Optional<FindIterable<Terminal>> findLastGeneratedTerminalID(String generatedTerminalID) {
        return Optional.ofNullable(this.collection.find(Filters.eq("generatedTerminalID", generatedTerminalID)).
                sort(Sorts.descending("generatedTerminalID")).limit(1));

    }

Вот обновленный репозиторий

private JacksonMongoCollection<Sequence> collection;

    public SequenceRepository(JacksonMongoCollection<Sequence> collection) {
        this.collection = collection;
    }


public Sequence save(Sequence sequence) {
    collection.save(sequence);
    return sequence;
}

public Sequence findAllSequences(Sequence sequence) {
    return collection.find(Filters.eq("generatedTerminalID", sequence.getGeneratedTerminalID())).first();
}

общедоступный BaseResponse generateTerminalIDs (TerminalIDDTO terminalDto) {

Sequence sequence = new Sequence();
sequence.setNext(0);
sequenceRepository.save(sequence);

int totalLength = 8;
int numberOfIds = terminalDto.getNumberOfTerminals();
int countRemainingSymbols = totalLength - START.length();
//there should be only 1 row at all times
sequence = this.sequenceRepository.findAllSequences(sequence);
int start = sequence.getNext();//start generation of sequences from the value of next
int next = start + numberOfIds;//this will be next value of sequence.next
for (int i = start; i < next; i++) {
    StringBuilder end = new StringBuilder();
    int current = i;
    int remainder = current % ALPHANUMERIC.length();//the index of next character
    do {
        end.append(ALPHANUMERIC.charAt(remainder));
        current /= ALPHANUMERIC.length();//update to check if we need to add more characters
        remainder = current % ALPHANUMERIC.length();//update index, only used if more chars are needed
    } while (current > 0);
    int padCount = countRemainingSymbols - end.length();
    StringBuilder result = new StringBuilder(START).append("-");//- is for easier debugging, remove it for your case
    for (int j = 0; j < padCount; j++) {
        result.append("0");
    }
    result.append(end.reverse());
    log.info("These are the values {}", result);
}
//update next value and save in db
sequence.setNext(next);
sequenceRepository.save(sequence);

return BaseResponse.builder().status(true).message("TerminalIDs have been generated").build();

}

Я хочу, чтобы сохранение и проверка того, существует ли оно, выполнялись в этом методе, который я разместил выше. Как лучше всего это сделать?

@chaosfire вот продолжение вопроса, который я задал ранее.

Curious 16.03.2022 23:18

Должен ли идентификатор быть уникальным во всей базе данных? Или он уникален только в конкретном наборе терминалов, например set1(id - 0000, 0001, 0002 и т.д.), set2(id - 0000, 0001 и т.д.)?

Chaosfire 17.03.2022 16:13

Он должен быть уникальным во всей базе данных.

Curious 17.03.2022 16:17
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете сделать это, добавив новую таблицу в БД. Поскольку он должен быть уникальным для всей базы данных, эта таблица будет содержать одну строку, в которой отслеживается следующее целое число, используемое для генерации идентификатора.

Я предполагаю, что вы используете данные весны, тогда ваша сущность может быть примерно такой:

public class Sequence {

  private String id;
  private int next;

  //getters and setters
}

Репозиторий:

@Repository
public interface SequenceRepository extends MongoRepository<Sequence, String> {
}

Предполагая, что вы используете монго из тега вопроса.

Начальное значение для next должно быть равно нулю.

Sequence sequence = new Sequence();
sequence.setNext(0);
this.repository.saveAndFlush(sequence);

Инициализируйте и сохраните в БД в нужное время, возможно, при запуске приложения. Просто сделайте эту инициализацию только один раз.

Тогда метод генерации может быть таким:

@Autowired
private SequenceRepository repository;

public BaseResponse generateTerminalIDs(TerminalIDDTO terminalDto) {
  Terminal terminal = new Terminal();
  int totalLength = 8;
  int numberOfIds = terminalDto.getNumberOfTerminals();
  int countRemainingSymbols = totalLength - START.length();
  //there should be only 1 row at all times
  Sequence sequence = this.repository.findAll().get(0);
  int start = sequence.getNext();//start generation of sequences from the value of next
  int next = start + numberOfIds;//this will be next value of sequence.next
  for (int i = start; i < next; i++) {
    StringBuilder end = new StringBuilder();
    int current = i;
    int remainder = current % ALPHANUMERIC.length();//the index of next character
    do {
      end.append(ALPHANUMERIC.charAt(remainder));
      current /= ALPHANUMERIC.length();//update to check if we need to add more characters
      remainder = current % ALPHANUMERIC.length();//update index, only used if more chars are needed
    } while (current > 0);
    int padCount = countRemainingSymbols - end.length();
    StringBuilder result = new StringBuilder(START).append("-");//- is for easier debugging, remove it for your case
    for (int j = 0; j < padCount; j++) {
      result.append("0");
    }
    //this should be outside pad loop
    result.append(end.reverse());
  }
  //update next value and save in db
  sequence.setNext(next);
  this.repository.saveAndFlush(sequence);
  return BaseResponse.builder().status(true).message("TerminalIDs have been generated").build();
}

Здесь есть некоторые предположения, но это общий алгоритм, которому вы должны следовать.

Важный: Это решение не учитывает возможность одновременного доступа к таблице, что может привести к дублированию идентификаторов. Если у вас есть такие варианты использования, вы можете рассмотреть:

  1. Блокировка таблицы во время выполнения generateTerminalIDs, что заставляет другие потоки, которым нужен доступ для следующего, ждать, пока не будут сгенерированы все идентификаторы.
  2. Получите следующий и обновите его сразу после, до генерации идентификатора. Блокировка таблицы во время получения и обновления может быть хорошей идеей, но другие потоки, которым нужен доступ, будут ждать меньше.

Редактировать: SaveAndFlush эквивалентен для создания или обновления. Весной это реализовано таким образом - если у объекта есть свойство id (в данном случае sequence.id != null), сделайте обновление, иначе создайте (вставьте). В вашем случае создайте строку при инициализации новой таблицы, обновите ее при создании идентификаторов.

О findAll() - он возвращает список со всеми строками/сущностями из таблицы. Сюда repository.findAll() вернется List<Sequence>. repository.findAll().get(0) вернет Sequence, строку первый и единственный в таблице.

Большое спасибо. Наличие некоторых проблем. Я не использую Springboot. Таким образом, у меня нет доступа к saveAndFlush(). Кроме того, отсутствует findAll.get(0). Что вернет findAll.get(0), чтобы я мог лучше понять, как реализовать здесь. В настоящее время думаю об использовании find.first() в MongoJackson.

Curious 21.03.2022 11:11

@Curious Проверьте редактирование.

Chaosfire 21.03.2022 14:41

В настоящее время только 0, и введенное число сохраняется в БД. Я обновлю вопрос, сохранив и найдя все эквиваленты, которые я создал. Кроме того, в какой части кода я должен разместить эту последовательность sequence = new Sequence(); последовательность.setNext (0); this.repository.saveAndFlush (последовательность); внутри функции, где она генерируется, или снаружи

Curious 23.03.2022 14:48

@ Любопытно, я не совсем понимаю первый вопрос. Что такое введенное число? Насчет второго вопроса, куда ставить - ... sequence.setNext(0); ..., однозначно снаружи, это инициализация вашей последовательности. Процитирую себя - Initialise and save in db at appropriate time, maybe app startup. Just do this initialization only once.

Chaosfire 23.03.2022 16:34

Первый вопрос я имел в виду terminalDto. Проблема в том, что последовательность (то есть идентификатор терминала) не сохраняется, и если я удалю то, что у меня есть в БД, это выдаст ошибку, что последовательность равна нулю

Curious 23.03.2022 16:49

@ Любопытно, я не эксперт по монго, но, насколько мне известно, collection.save() следует вставлять или обновлять, в зависимости от того, есть ли идентификатор. Боюсь, недостаточно данных для решения этой проблемы, по крайней мере, для меня. Моя единственная идея заключается в том, что если проблема возникает только при обновлении последовательности, вы можете использовать некоторые из методов collection.update...(), но это выстрел в темноту.

Chaosfire 23.03.2022 19:02

Большое спасибо. Итак, я нашел способ сохранить, единственная сложность сейчас - сохранить список (последовательности). Это все, что осталось

Curious 24.03.2022 12:49

Внес некоторые изменения и получил желаемый результат. Спасибо!

Curious 25.03.2022 13:43

Другие вопросы по теме