如何在 mongodb 中保存字母数字序列并从 MongoDB 中最后保存的序列开始生成

发布于 2025-01-14 17:11:21 字数 2798 浏览 4 评论 0原文

我有一种方法可以根据特定模式生成字母数字序列。我想保存生成的序列,当下次我想生成一个新的序列时,它应该从最后保存的序列开始。我对这种情况有疑问,因为它是字母数字的。另外,我想将生成的 ID 放入 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();
}

public BaseResponsegenerateTerminalIDs(TerminalIDDTOterminalDto) {

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();

}

我希望在我上面发布的方法中保存并检查它是否存在。最好的方法是什么?

I have a method that generates an alphanumeric sequence based on a particular pattern. I want to save the generated sequence and when next I want to generate a new one, it should start from the last saved one. I am having an issue with this happening because it is alphanumeric. Also, I want to put the generated IDs in an excel file.

These two methods below check if it already exists and also try to fetch the last item saved.

 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));

    }

Here is the updated repository

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();
}

public 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();

}

I want the saving and checking if it exists to be done in this method I posted above. What is the best way to go about it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

酷到爆炸 2025-01-21 17:11:21

您可以将新表添加到数据库中。由于它对于整个数据库必须是唯一的,因此该表将保存一行,用于跟踪用于 id 生成的下一个整数。

我假设您使用 spring 数据,那么您的实体可能是这样的:

public class Sequence {

  private String id;
  private int next;

  //getters and setters
}

存储库:

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

假设您正在使用问题标签中的 mongo。

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();
}

这里有一些假设,但这是您应该遵循的整体算法。

重要提示:此解决方案没有考虑可能同时访问表的情况,这可能会导致 id 重复。如果您有这样的用例,您可能需要考虑:

  1. generateTerminalIDs 执行期间锁定表,从而强制其他想要访问 next 的线程等待,直到生成所有 id。
  2. 获取下一个,并在 id 生成之前立即更新它。在获取和更新期间锁定表可能仍然是一个好主意,但需要访问的其他线程将等待更少的时间。

编辑: SaveAndFlush 相当于创建或更新。在 Spring 中,它以这种方式实现 - 如果实体具有 id 属性(在本例中为 sequence.id != null),则执行更新,否则执行创建(插入)。对于您的情况,在初始化新表时创建行,在创建 ids 时更新它。

关于 findAll() - 它返回一个包含表中所有行/实体的列表。这里repository.findAll()将返回Listrepository.findAll().get(0) 将返回 Sequence,即表中的第一行也是唯一行。

You could do it adding a new table to db. Since it has to be unique for entire db, this table will hold a single row, which keeps track of next integer to use for id generation.

I'll assume you use spring data, then your entity could be something like this:

public class Sequence {

  private String id;
  private int next;

  //getters and setters
}

The repository:

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

Assuming you are using mongo from question tag.

Initial value for next should be zero.

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

Initialise and save in db at appropriate time, maybe app startup. Just do this initialization only once.

Then generation method might be like this:

@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();
}

There are some assumptions here, but this is the overall algorithm you should follow.

Important: This solution does not take into account possible simultaneous access to the table, which may lead to duplicating ids. If you have such use cases, you might want to consider:

  1. Locking the table during generateTerminalIDs execution, thus forcing other threads who want access for next to wait until all ids are generated.
  2. Get next, and update it right after, before id generation. Locking the table during get and update may still be a good idea, but other threads that want access will wait less.

Edit: SaveAndFlush is equivalent for create or update. In spring it's implemented in this way - if entity has id property(sequence.id != null in this case), do an update, otherwise do create(insert). For your case, create the row when initializing new table, update it when ids are created.

About findAll() - it returns a list with all rows/entites from a table. Here repository.findAll() will return List<Sequence>. repository.findAll().get(0) will return Sequence, the first and only row in the table.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文