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

How to save alphanumeric sequence in mongodb and start generating from the last saved sequence in MongoDB

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

}

我想保存并检查它是否存在,用我上面发布的这个方法来完成。最好的方法是什么?

您可以将新的 table 添加到数据库中。由于它对于整个数据库必须是唯一的,因此 table 将保留一行,跟踪下一个用于生成 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();
}

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

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

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

编辑: SaveAndFlush 等同于创建或更新。在 spring 中,它以这种方式实现 - 如果实体具有 id 属性(在这种情况下为 sequence.id != null),则进行更新,否则进行创建(插入)。对于您的情况,在初始化新 table 时创建行,在创建 ID 时更新它。

关于 findAll() - 它 return 是一个包含来自 table 的所有 rows/entites 的列表。这里repository.findAll()将returnList<Sequence>repository.findAll().get(0) 将 return Sequence第一个也是唯一的 行在 table.